Changeset View
Changeset View
Standalone View
Standalone View
source/blender/modifiers/intern/MOD_weld.c
| Show All 21 Lines | |||||
| * | * | ||||
| * Weld modifier: Remove doubles. | * Weld modifier: Remove doubles. | ||||
| */ | */ | ||||
| /* TODOs: | /* TODOs: | ||||
| * - Review weight and vertex color interpolation.; | * - Review weight and vertex color interpolation.; | ||||
| */ | */ | ||||
| //#define USE_WELD_DEBUG | |||||
| //#define USE_WELD_NORMALS | |||||
| //#define USE_BVHTREEKDOP | |||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||
| #include "BLI_alloca.h" | #include "BLI_alloca.h" | ||||
| #include "BLI_kdopbvh.h" | #include "BLI_bitmap.h" | ||||
| #include "BLI_kdtree.h" | |||||
| #include "BLI_math.h" | #include "BLI_math.h" | ||||
| #include "BLT_translation.h" | #include "BLT_translation.h" | ||||
| #include "DNA_mesh_types.h" | #include "DNA_mesh_types.h" | ||||
| #include "DNA_meshdata_types.h" | #include "DNA_meshdata_types.h" | ||||
| #include "DNA_modifier_types.h" | #include "DNA_modifier_types.h" | ||||
| #include "DNA_object_types.h" | #include "DNA_object_types.h" | ||||
| #include "DNA_screen_types.h" | #include "DNA_screen_types.h" | ||||
| #ifdef USE_BVHTREEKDOP | |||||
| #include "BKE_bvhutils.h" | # include "BKE_bvhutils.h" | ||||
| #endif | |||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||
| #include "BKE_deform.h" | #include "BKE_deform.h" | ||||
| #include "BKE_mesh.h" | #include "BKE_mesh.h" | ||||
| #include "BKE_modifier.h" | #include "BKE_modifier.h" | ||||
| #include "BKE_screen.h" | #include "BKE_screen.h" | ||||
| #include "UI_interface.h" | #include "UI_interface.h" | ||||
| #include "UI_resources.h" | #include "UI_resources.h" | ||||
| #include "RNA_access.h" | #include "RNA_access.h" | ||||
| #include "DEG_depsgraph.h" | #include "DEG_depsgraph.h" | ||||
| #include "MOD_modifiertypes.h" | #include "MOD_modifiertypes.h" | ||||
| #include "MOD_ui_common.h" | #include "MOD_ui_common.h" | ||||
| //#define USE_WELD_DEBUG | |||||
| //#define USE_WELD_NORMALS | |||||
| /* Indicates when the element was not computed. */ | /* Indicates when the element was not computed. */ | ||||
| #define OUT_OF_CONTEXT (uint)(-1) | #define OUT_OF_CONTEXT (uint)(-1) | ||||
| /* Indicates if the edge or face will be collapsed. */ | /* Indicates if the edge or face will be collapsed. */ | ||||
| #define ELEM_COLLAPSED (uint)(-2) | #define ELEM_COLLAPSED (uint)(-2) | ||||
| /* indicates whether an edge or vertex in groups_map will be merged. */ | /* indicates whether an edge or vertex in groups_map will be merged. */ | ||||
| #define ELEM_MERGED (uint)(-2) | #define ELEM_MERGED (uint)(-2) | ||||
| /* Used to indicate a range in an array specifying a group. */ | /* Used to indicate a range in an array specifying a group. */ | ||||
| ▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | union { | ||||
| }; | }; | ||||
| }; | }; | ||||
| } WeldPoly; | } WeldPoly; | ||||
| typedef struct WeldMesh { | typedef struct WeldMesh { | ||||
| /* Group of vertices to be merged. */ | /* Group of vertices to be merged. */ | ||||
| struct WeldGroup *vert_groups; | struct WeldGroup *vert_groups; | ||||
| uint *vert_groups_buffer; | uint *vert_groups_buffer; | ||||
| /* From the original index of the vertex, this indicates which group it is or is going to be | |||||
| * merged. */ | |||||
| uint *vert_groups_map; | |||||
| /* Group of edges to be merged. */ | /* Group of edges to be merged. */ | ||||
| struct WeldGroupEdge *edge_groups; | struct WeldGroupEdge *edge_groups; | ||||
| uint *edge_groups_buffer; | uint *edge_groups_buffer; | ||||
| /* From the original index of the vertex, this indicates which group it is or is going to be | /* From the original index of the vertex, this indicates which group it is or is going to be | ||||
| * merged. */ | * merged. */ | ||||
| uint *edge_groups_map; | uint *edge_groups_map; | ||||
| ▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter, | ||||
| const WeldPoly *wp, | const WeldPoly *wp, | ||||
| const WeldLoop *wloop, | const WeldLoop *wloop, | ||||
| const MLoop *mloop, | const MLoop *mloop, | ||||
| const uint *loop_map, | const uint *loop_map, | ||||
| uint *group_buffer); | uint *group_buffer); | ||||
| static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter); | static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter); | ||||
| static void weld_assert_vert_dest_map_setup(const BVHTreeOverlap *overlap, | |||||
| const uint overlap_len, | |||||
| const uint *vert_dest_map) | |||||
| { | |||||
| const BVHTreeOverlap *overlap_iter = &overlap[0]; | |||||
| for (uint i = overlap_len; i--; overlap_iter++) { | |||||
| uint indexA = overlap_iter->indexA; | |||||
| uint indexB = overlap_iter->indexB; | |||||
| uint va_dst = vert_dest_map[indexA]; | |||||
| uint vb_dst = vert_dest_map[indexB]; | |||||
| BLI_assert(va_dst == vb_dst); | |||||
| } | |||||
| } | |||||
| static void weld_assert_edge_kill_len(const WeldEdge *wedge, | static void weld_assert_edge_kill_len(const WeldEdge *wedge, | ||||
| const uint wedge_len, | const uint wedge_len, | ||||
| const uint supposed_kill_len) | const uint supposed_kill_len) | ||||
| { | { | ||||
| uint kills = 0; | uint kills = 0; | ||||
| const WeldEdge *we = &wedge[0]; | const WeldEdge *we = &wedge[0]; | ||||
| for (uint i = wedge_len; i--; we++) { | for (uint i = wedge_len; i--; we++) { | ||||
| uint edge_dest = we->edge_dest; | uint edge_dest = we->edge_dest; | ||||
| ▲ Show 20 Lines • Show All 150 Lines • ▼ Show 20 Lines | |||||
| #endif | #endif | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Weld Vert API | /** \name Weld Vert API | ||||
| * \{ */ | * \{ */ | ||||
| static void weld_vert_ctx_alloc_and_setup(const uint mvert_len, | static void weld_vert_ctx_alloc_and_setup(const uint mvert_len, | ||||
| const BVHTreeOverlap *overlap, | |||||
| const uint overlap_len, | |||||
| uint *r_vert_dest_map, | uint *r_vert_dest_map, | ||||
| WeldVert **r_wvert, | WeldVert **r_wvert, | ||||
| uint *r_wvert_len, | uint *r_wvert_len) | ||||
| uint *r_vert_kill_len) | |||||
| { | { | ||||
| range_vn_u(r_vert_dest_map, mvert_len, 0); | |||||
| uint vert_kill_len = 0; | |||||
| const BVHTreeOverlap *overlap_iter = &overlap[0]; | |||||
| for (uint i = 0; i < overlap_len; i++, overlap_iter++) { | |||||
| uint indexA = overlap_iter->indexA; | |||||
| uint indexB = overlap_iter->indexB; | |||||
| BLI_assert(indexA < indexB); | |||||
| uint va_dst = r_vert_dest_map[indexA]; | |||||
| while (va_dst != r_vert_dest_map[va_dst]) { | |||||
| va_dst = r_vert_dest_map[va_dst]; | |||||
| } | |||||
| uint vb_dst = r_vert_dest_map[indexB]; | |||||
| while (vb_dst != r_vert_dest_map[vb_dst]) { | |||||
| vb_dst = r_vert_dest_map[vb_dst]; | |||||
| } | |||||
| if (va_dst == vb_dst) { | |||||
| continue; | |||||
| } | |||||
| if (va_dst > vb_dst) { | |||||
| SWAP(uint, va_dst, vb_dst); | |||||
| } | |||||
| vert_kill_len++; | |||||
| r_vert_dest_map[vb_dst] = va_dst; | |||||
| } | |||||
| /* Fix #r_vert_dest_map for next step. */ | |||||
| for (uint i = 0; i < mvert_len; i++) { | |||||
| if (i == r_vert_dest_map[i]) { | |||||
| r_vert_dest_map[i] = OUT_OF_CONTEXT; | |||||
| continue; | |||||
| } | |||||
| uint v = i; | |||||
| while (v != r_vert_dest_map[v] && r_vert_dest_map[v] != OUT_OF_CONTEXT) { | |||||
| v = r_vert_dest_map[v]; | |||||
| } | |||||
| r_vert_dest_map[v] = v; | |||||
| r_vert_dest_map[i] = v; | |||||
| } | |||||
| /* Vert Context. */ | /* Vert Context. */ | ||||
| uint wvert_len = 0; | uint wvert_len = 0; | ||||
| WeldVert *wvert, *wv; | WeldVert *wvert, *wv; | ||||
| wvert = MEM_mallocN(sizeof(*wvert) * mvert_len, __func__); | wvert = MEM_mallocN(sizeof(*wvert) * mvert_len, __func__); | ||||
| wv = &wvert[0]; | wv = &wvert[0]; | ||||
| uint *v_dest_iter = &r_vert_dest_map[0]; | uint *v_dest_iter = &r_vert_dest_map[0]; | ||||
| for (uint i = 0; i < mvert_len; i++, v_dest_iter++) { | for (uint i = 0; i < mvert_len; i++, v_dest_iter++) { | ||||
| if (*v_dest_iter != OUT_OF_CONTEXT) { | if (*v_dest_iter != OUT_OF_CONTEXT) { | ||||
| wv->vert_dest = *v_dest_iter; | wv->vert_dest = *v_dest_iter; | ||||
| wv->vert_orig = i; | wv->vert_orig = i; | ||||
| wv++; | wv++; | ||||
| wvert_len++; | wvert_len++; | ||||
| } | } | ||||
| } | } | ||||
| #ifdef USE_WELD_DEBUG | |||||
| weld_assert_vert_dest_map_setup(overlap, overlap_len, r_vert_dest_map); | |||||
| #endif | |||||
| *r_wvert = MEM_reallocN(wvert, sizeof(*wvert) * wvert_len); | *r_wvert = MEM_reallocN(wvert, sizeof(*wvert) * wvert_len); | ||||
| *r_wvert_len = wvert_len; | *r_wvert_len = wvert_len; | ||||
| *r_vert_kill_len = vert_kill_len; | |||||
| } | } | ||||
| static void weld_vert_groups_setup(const uint mvert_len, | static void weld_vert_groups_setup(const uint mvert_len, | ||||
| const uint wvert_len, | const uint wvert_len, | ||||
| const WeldVert *wvert, | const WeldVert *wvert, | ||||
| const uint *vert_dest_map, | const uint *vert_dest_map, | ||||
| uint *r_vert_groups_map, | uint *r_vert_groups_map, | ||||
| uint **r_vert_groups_buffer, | uint **r_vert_groups_buffer, | ||||
| ▲ Show 20 Lines • Show All 909 Lines • ▼ Show 20 Lines | |||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Weld Mesh API | /** \name Weld Mesh API | ||||
| * \{ */ | * \{ */ | ||||
| static void weld_mesh_context_create(const Mesh *mesh, | static void weld_mesh_context_create(const Mesh *mesh, | ||||
| BVHTreeOverlap *overlap, | uint *vert_dest_map, | ||||
| const uint overlap_len, | const uint vert_kill_len, | ||||
| WeldMesh *r_weld_mesh) | WeldMesh *r_weld_mesh) | ||||
| { | { | ||||
| const MEdge *medge = mesh->medge; | const MEdge *medge = mesh->medge; | ||||
| const MLoop *mloop = mesh->mloop; | const MLoop *mloop = mesh->mloop; | ||||
| const MPoly *mpoly = mesh->mpoly; | const MPoly *mpoly = mesh->mpoly; | ||||
| const uint mvert_len = mesh->totvert; | const uint mvert_len = mesh->totvert; | ||||
| const uint medge_len = mesh->totedge; | const uint medge_len = mesh->totedge; | ||||
| const uint mloop_len = mesh->totloop; | const uint mloop_len = mesh->totloop; | ||||
| const uint mpoly_len = mesh->totpoly; | const uint mpoly_len = mesh->totpoly; | ||||
| uint *vert_dest_map = MEM_mallocN(sizeof(*vert_dest_map) * mvert_len, __func__); | |||||
| uint *edge_dest_map = MEM_mallocN(sizeof(*edge_dest_map) * medge_len, __func__); | uint *edge_dest_map = MEM_mallocN(sizeof(*edge_dest_map) * medge_len, __func__); | ||||
| struct WeldGroup *v_links = MEM_callocN(sizeof(*v_links) * mvert_len, __func__); | struct WeldGroup *v_links = MEM_callocN(sizeof(*v_links) * mvert_len, __func__); | ||||
| WeldVert *wvert; | WeldVert *wvert; | ||||
| uint wvert_len; | uint wvert_len; | ||||
| weld_vert_ctx_alloc_and_setup(mvert_len, | r_weld_mesh->vert_kill_len = vert_kill_len; | ||||
| overlap, | weld_vert_ctx_alloc_and_setup(mvert_len, vert_dest_map, &wvert, &wvert_len); | ||||
| overlap_len, | |||||
| vert_dest_map, | |||||
| &wvert, | |||||
| &wvert_len, | |||||
| &r_weld_mesh->vert_kill_len); | |||||
| uint *edge_ctx_map; | uint *edge_ctx_map; | ||||
| WeldEdge *wedge; | WeldEdge *wedge; | ||||
| uint wedge_len; | uint wedge_len; | ||||
| weld_edge_ctx_alloc( | weld_edge_ctx_alloc( | ||||
| medge, medge_len, vert_dest_map, edge_dest_map, &edge_ctx_map, &wedge, &wedge_len); | medge, medge_len, vert_dest_map, edge_dest_map, &edge_ctx_map, &wedge, &wedge_len); | ||||
| weld_edge_ctx_setup( | weld_edge_ctx_setup( | ||||
| Show All 26 Lines | weld_edge_groups_setup(medge_len, | ||||
| r_weld_mesh->edge_kill_len, | r_weld_mesh->edge_kill_len, | ||||
| wedge_len, | wedge_len, | ||||
| wedge, | wedge, | ||||
| edge_ctx_map, | edge_ctx_map, | ||||
| edge_dest_map, | edge_dest_map, | ||||
| &r_weld_mesh->edge_groups_buffer, | &r_weld_mesh->edge_groups_buffer, | ||||
| &r_weld_mesh->edge_groups); | &r_weld_mesh->edge_groups); | ||||
| r_weld_mesh->vert_groups_map = vert_dest_map; | |||||
| r_weld_mesh->edge_groups_map = edge_dest_map; | r_weld_mesh->edge_groups_map = edge_dest_map; | ||||
| MEM_freeN(v_links); | MEM_freeN(v_links); | ||||
| MEM_freeN(wvert); | MEM_freeN(wvert); | ||||
| MEM_freeN(edge_ctx_map); | MEM_freeN(edge_ctx_map); | ||||
| MEM_freeN(wedge); | MEM_freeN(wedge); | ||||
| } | } | ||||
| static void weld_mesh_context_free(WeldMesh *weld_mesh) | static void weld_mesh_context_free(WeldMesh *weld_mesh) | ||||
| { | { | ||||
| MEM_freeN(weld_mesh->vert_groups); | MEM_freeN(weld_mesh->vert_groups); | ||||
| MEM_freeN(weld_mesh->vert_groups_buffer); | MEM_freeN(weld_mesh->vert_groups_buffer); | ||||
| MEM_freeN(weld_mesh->vert_groups_map); | |||||
| MEM_freeN(weld_mesh->edge_groups); | MEM_freeN(weld_mesh->edge_groups); | ||||
| MEM_freeN(weld_mesh->edge_groups_buffer); | MEM_freeN(weld_mesh->edge_groups_buffer); | ||||
| MEM_freeN(weld_mesh->edge_groups_map); | MEM_freeN(weld_mesh->edge_groups_map); | ||||
| MEM_freeN(weld_mesh->wloop); | MEM_freeN(weld_mesh->wloop); | ||||
| MEM_freeN(weld_mesh->wpoly); | MEM_freeN(weld_mesh->wpoly); | ||||
| MEM_freeN(weld_mesh->loop_map); | MEM_freeN(weld_mesh->loop_map); | ||||
| ▲ Show 20 Lines • Show All 142 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Weld Modifier Main | /** \name Weld Modifier Main | ||||
| * \{ */ | * \{ */ | ||||
| #ifdef USE_BVHTREEKDOP | |||||
| struct WeldOverlapData { | struct WeldOverlapData { | ||||
| const MVert *mvert; | const MVert *mvert; | ||||
| float merge_dist_sq; | float merge_dist_sq; | ||||
| }; | }; | ||||
| static bool bvhtree_weld_overlap_cb(void *userdata, int index_a, int index_b, int UNUSED(thread)) | static bool bvhtree_weld_overlap_cb(void *userdata, int index_a, int index_b, int UNUSED(thread)) | ||||
| { | { | ||||
| if (index_a < index_b) { | if (index_a < index_b) { | ||||
| struct WeldOverlapData *data = userdata; | struct WeldOverlapData *data = userdata; | ||||
| const MVert *mvert = data->mvert; | const MVert *mvert = data->mvert; | ||||
| const float dist_sq = len_squared_v3v3(mvert[index_a].co, mvert[index_b].co); | const float dist_sq = len_squared_v3v3(mvert[index_a].co, mvert[index_b].co); | ||||
| BLI_assert(dist_sq <= ((data->merge_dist_sq + FLT_EPSILON) * 3)); | BLI_assert(dist_sq <= ((data->merge_dist_sq + FLT_EPSILON) * 3)); | ||||
| return dist_sq <= data->merge_dist_sq; | return dist_sq <= data->merge_dist_sq; | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| #endif | |||||
| static Mesh *weldModifier_doWeld(WeldModifierData *wmd, const ModifierEvalContext *ctx, Mesh *mesh) | static Mesh *weldModifier_doWeld(WeldModifierData *wmd, const ModifierEvalContext *ctx, Mesh *mesh) | ||||
| { | { | ||||
| Mesh *result = mesh; | Mesh *result = mesh; | ||||
| Object *ob = ctx->object; | Object *ob = ctx->object; | ||||
| BLI_bitmap *v_mask = NULL; | BLI_bitmap *v_mask = NULL; | ||||
| int v_mask_act = 0; | int v_mask_act = 0; | ||||
| Show All 21 Lines | if (dvert) { | ||||
| if (found != invert_vgroup) { | if (found != invert_vgroup) { | ||||
| BLI_BITMAP_ENABLE(v_mask, i); | BLI_BITMAP_ENABLE(v_mask, i); | ||||
| v_mask_act++; | v_mask_act++; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* From the original index of the vertex. | |||||
| * This indicates which vert it is or is going to be merged. */ | |||||
| uint *vert_dest_map = MEM_malloc_arrayN(totvert, sizeof(*vert_dest_map), __func__); | |||||
| uint vert_kill_len = 0; | |||||
| #ifdef USE_BVHTREEKDOP | |||||
| { | |||||
| /* Get overlap map. */ | /* Get overlap map. */ | ||||
| /* TODO: For a better performanse use KD-Tree. */ | |||||
| struct BVHTreeFromMesh treedata; | struct BVHTreeFromMesh treedata; | ||||
| BVHTree *bvhtree = bvhtree_from_mesh_verts_ex(&treedata, | BVHTree *bvhtree = bvhtree_from_mesh_verts_ex(&treedata, | ||||
| mvert, | mvert, | ||||
| totvert, | totvert, | ||||
| false, | false, | ||||
| v_mask, | v_mask, | ||||
| v_mask_act, | v_mask_act, | ||||
| wmd->merge_dist / 2, | wmd->merge_dist / 2, | ||||
| 2, | 2, | ||||
| 6, | 6, | ||||
| 0, | 0, | ||||
| NULL, | NULL, | ||||
| NULL); | NULL); | ||||
| if (v_mask) { | if (bvhtree) { | ||||
| MEM_freeN(v_mask); | |||||
| } | |||||
| if (bvhtree == NULL) { | |||||
| return result; | |||||
| } | |||||
| struct WeldOverlapData data; | struct WeldOverlapData data; | ||||
| data.mvert = mvert; | data.mvert = mvert; | ||||
| data.merge_dist_sq = square_f(wmd->merge_dist); | data.merge_dist_sq = square_f(wmd->merge_dist); | ||||
| uint overlap_len; | uint overlap_len; | ||||
| BVHTreeOverlap *overlap = BLI_bvhtree_overlap_ex(bvhtree, | BVHTreeOverlap *overlap = BLI_bvhtree_overlap_ex(bvhtree, | ||||
| bvhtree, | bvhtree, | ||||
| &overlap_len, | &overlap_len, | ||||
| bvhtree_weld_overlap_cb, | bvhtree_weld_overlap_cb, | ||||
| &data, | &data, | ||||
| wmd->max_interactions, | 1, | ||||
| BVH_OVERLAP_RETURN_PAIRS); | BVH_OVERLAP_RETURN_PAIRS); | ||||
| free_bvhtree_from_mesh(&treedata); | free_bvhtree_from_mesh(&treedata); | ||||
| if (overlap) { | |||||
| range_vn_u(vert_dest_map, totvert, 0); | |||||
| const BVHTreeOverlap *overlap_iter = &overlap[0]; | |||||
| for (uint i = 0; i < overlap_len; i++, overlap_iter++) { | |||||
| uint indexA = overlap_iter->indexA; | |||||
| uint indexB = overlap_iter->indexB; | |||||
| BLI_assert(indexA < indexB); | |||||
| uint va_dst = vert_dest_map[indexA]; | |||||
| while (va_dst != vert_dest_map[va_dst]) { | |||||
| va_dst = vert_dest_map[va_dst]; | |||||
| } | |||||
| uint vb_dst = vert_dest_map[indexB]; | |||||
| while (vb_dst != vert_dest_map[vb_dst]) { | |||||
| vb_dst = vert_dest_map[vb_dst]; | |||||
| } | |||||
| if (va_dst == vb_dst) { | |||||
| continue; | |||||
| } | |||||
| if (va_dst > vb_dst) { | |||||
| SWAP(uint, va_dst, vb_dst); | |||||
| } | |||||
| vert_kill_len++; | |||||
| vert_dest_map[vb_dst] = va_dst; | |||||
| } | |||||
| /* Fix #r_vert_dest_map for next step. */ | |||||
| for (uint i = 0; i < totvert; i++) { | |||||
| if (i == vert_dest_map[i]) { | |||||
| vert_dest_map[i] = OUT_OF_CONTEXT; | |||||
| } | |||||
| else { | |||||
| uint v = i; | |||||
| while (v != vert_dest_map[v] && vert_dest_map[v] != OUT_OF_CONTEXT) { | |||||
| v = vert_dest_map[v]; | |||||
| } | |||||
| vert_dest_map[v] = v; | |||||
| vert_dest_map[i] = v; | |||||
| } | |||||
| } | |||||
| MEM_freeN(overlap); | |||||
| } | |||||
| } | |||||
| } | |||||
| #else | |||||
| { | |||||
| vert_dest_map = MEM_malloc_arrayN(totvert, sizeof(*vert_dest_map), __func__); | |||||
| KDTree_3d *tree = BLI_kdtree_3d_new(totvert); | |||||
| for (i = 0; i < totvert; i++) { | |||||
| if (!(v_mask && !BLI_BITMAP_TEST(v_mask, i))) { | |||||
| BLI_kdtree_3d_insert(tree, i, mvert[i].co); | |||||
| } | |||||
| vert_dest_map[i] = OUT_OF_CONTEXT; | |||||
| } | |||||
| if (overlap_len) { | BLI_kdtree_3d_balance(tree); | ||||
| vert_kill_len = BLI_kdtree_3d_calc_duplicates_fast( | |||||
| tree, wmd->merge_dist, false, (int *)vert_dest_map); | |||||
| BLI_kdtree_3d_free(tree); | |||||
| } | |||||
| #endif | |||||
| if (v_mask) { | |||||
| MEM_freeN(v_mask); | |||||
| } | |||||
| if (vert_kill_len) { | |||||
| WeldMesh weld_mesh; | WeldMesh weld_mesh; | ||||
| weld_mesh_context_create(mesh, overlap, overlap_len, &weld_mesh); | weld_mesh_context_create(mesh, vert_dest_map, vert_kill_len, &weld_mesh); | ||||
| mloop = mesh->mloop; | mloop = mesh->mloop; | ||||
| mpoly = mesh->mpoly; | mpoly = mesh->mpoly; | ||||
| totedge = mesh->totedge; | totedge = mesh->totedge; | ||||
| totloop = mesh->totloop; | totloop = mesh->totloop; | ||||
| totpoly = mesh->totpoly; | totpoly = mesh->totpoly; | ||||
| const int result_nverts = totvert - weld_mesh.vert_kill_len; | const int result_nverts = totvert - weld_mesh.vert_kill_len; | ||||
| const int result_nedges = totedge - weld_mesh.edge_kill_len; | const int result_nedges = totedge - weld_mesh.edge_kill_len; | ||||
| const int result_nloops = totloop - weld_mesh.loop_kill_len; | const int result_nloops = totloop - weld_mesh.loop_kill_len; | ||||
| const int result_npolys = totpoly - weld_mesh.poly_kill_len + weld_mesh.wpoly_new_len; | const int result_npolys = totpoly - weld_mesh.poly_kill_len + weld_mesh.wpoly_new_len; | ||||
| result = BKE_mesh_new_nomain_from_template( | result = BKE_mesh_new_nomain_from_template( | ||||
| mesh, result_nverts, result_nedges, 0, result_nloops, result_npolys); | mesh, result_nverts, result_nedges, 0, result_nloops, result_npolys); | ||||
| /* Vertices */ | /* Vertices */ | ||||
| uint *vert_final = weld_mesh.vert_groups_map; | uint *vert_final = vert_dest_map; | ||||
| uint *index_iter = &vert_final[0]; | uint *index_iter = &vert_final[0]; | ||||
| int dest_index = 0; | int dest_index = 0; | ||||
| for (i = 0; i < totvert; i++, index_iter++) { | for (i = 0; i < totvert; i++, index_iter++) { | ||||
| int source_index = i; | int source_index = i; | ||||
| int count = 0; | int count = 0; | ||||
| while (i < totvert && *index_iter == OUT_OF_CONTEXT) { | while (i < totvert && *index_iter == OUT_OF_CONTEXT) { | ||||
| *index_iter = dest_index + count; | *index_iter = dest_index + count; | ||||
| index_iter++; | index_iter++; | ||||
| ▲ Show 20 Lines • Show All 156 Lines • ▼ Show 20 Lines | if (vert_kill_len) { | ||||
| /* is this needed? */ | /* is this needed? */ | ||||
| /* recalculate normals */ | /* recalculate normals */ | ||||
| result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; | result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; | ||||
| weld_mesh_context_free(&weld_mesh); | weld_mesh_context_free(&weld_mesh); | ||||
| } | } | ||||
| MEM_freeN(overlap); | MEM_freeN(vert_dest_map); | ||||
| return result; | return result; | ||||
| } | } | ||||
| static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) | static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) | ||||
| { | { | ||||
| WeldModifierData *wmd = (WeldModifierData *)md; | WeldModifierData *wmd = (WeldModifierData *)md; | ||||
| return weldModifier_doWeld(wmd, ctx, mesh); | return weldModifier_doWeld(wmd, ctx, mesh); | ||||
| } | } | ||||
| static void initData(ModifierData *md) | static void initData(ModifierData *md) | ||||
| { | { | ||||
| WeldModifierData *wmd = (WeldModifierData *)md; | WeldModifierData *wmd = (WeldModifierData *)md; | ||||
| wmd->merge_dist = 0.001f; | wmd->merge_dist = 0.001f; | ||||
| wmd->max_interactions = 1; | |||||
| wmd->defgrp_name[0] = '\0'; | wmd->defgrp_name[0] = '\0'; | ||||
| } | } | ||||
| static void requiredDataMask(Object *UNUSED(ob), | static void requiredDataMask(Object *UNUSED(ob), | ||||
| ModifierData *md, | ModifierData *md, | ||||
| CustomData_MeshMasks *r_cddata_masks) | CustomData_MeshMasks *r_cddata_masks) | ||||
| { | { | ||||
| WeldModifierData *wmd = (WeldModifierData *)md; | WeldModifierData *wmd = (WeldModifierData *)md; | ||||
| Show All 9 Lines | static void panel_draw(const bContext *UNUSED(C), Panel *panel) | ||||
| uiLayout *layout = panel->layout; | uiLayout *layout = panel->layout; | ||||
| PointerRNA ob_ptr; | PointerRNA ob_ptr; | ||||
| PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr); | PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr); | ||||
| uiLayoutSetPropSep(layout, true); | uiLayoutSetPropSep(layout, true); | ||||
| uiItemR(layout, ptr, "merge_threshold", 0, IFACE_("Distance"), ICON_NONE); | uiItemR(layout, ptr, "merge_threshold", 0, IFACE_("Distance"), ICON_NONE); | ||||
| uiItemR(layout, ptr, "max_interactions", 0, NULL, ICON_NONE); | |||||
| modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); | modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); | ||||
| modifier_panel_end(layout, ptr); | modifier_panel_end(layout, ptr); | ||||
| } | } | ||||
| static void panelRegister(ARegionType *region_type) | static void panelRegister(ARegionType *region_type) | ||||
| { | { | ||||
| modifier_panel_register(region_type, eModifierType_Weld, panel_draw); | modifier_panel_register(region_type, eModifierType_Weld, panel_draw); | ||||
| Show All 39 Lines | |||||