Changeset View
Standalone View
source/blender/modifiers/intern/MOD_weld.c
| Show First 20 Lines • Show All 376 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, | struct WeldOverlapData { | ||||
| const BVHTreeOverlap *overlap, | const MVert *mvert; | ||||
| const uint overlap_len, | float merge_dist_sq; | ||||
| }; | |||||
| static bool bvhtree_weld_overlap_cb(void *userdata, int index_a, int index_b, int UNUSED(thread)) | |||||
| { | |||||
| if (index_a < index_b) { | |||||
| struct WeldOverlapData *data = userdata; | |||||
| const MVert *mvert = data->mvert; | |||||
| 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)); | |||||
| return dist_sq <= data->merge_dist_sq; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| static void weld_fix_vert_map(uint *vert_dest_map, int vert_dest_map_len) | |||||
mano-wii: I'm not sure if `"weld_fix_vert_map"` is an appropriate name
A comment here would be useful to… | |||||
weaselAuthorUnsubmitted Done Inline ActionsAgreed. Just for reference here: The vert_dest_map prior to this function is supposed to converge to the correct value when iterated (for fixpoints). This function will finalize this map by doing the iteration for every vert and writing the result. It also sets all verts that didn't get merged to OUT_OF_CONTEXT. weasel: Agreed. Just for reference here: The `vert_dest_map` prior to this function is supposed to… | |||||
| { | |||||
| for (uint i = 0; i < vert_dest_map_len; 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; | |||||
| } | |||||
| } | |||||
| } | |||||
| static void weld_bvh_find_overlaps(WeldModifierData *wmd, | |||||
| BLI_bitmap *v_mask, | |||||
| uint v_mask_act, | |||||
| Mesh *mesh, | |||||
| BVHTreeOverlap **overlap, | |||||
| uint *overlap_len) | |||||
| { | |||||
| const MVert *mvert = mesh->mvert; | |||||
| const MEdge *medge = mesh->medge; | |||||
| uint totvert = mesh->totvert; | |||||
| uint totedge = mesh->totedge; | |||||
| /* Get overlap map. */ | |||||
| /* TODO: For a better performance use KD-Tree. */ | |||||
| struct BVHTreeFromMesh treedata; | |||||
| BVHTree *bvhtree = bvhtree_from_mesh_verts_ex(&treedata, | |||||
Done Inline ActionsFrom what I can see here. Neither 'medge' nor 'totegde' are being used. mano-wii: From what I can see here. Neither 'medge' nor 'totegde' are being used. | |||||
| mvert, | |||||
| totvert, | |||||
| false, | |||||
| v_mask, | |||||
| v_mask_act, | |||||
| wmd->merge_dist / 2, | |||||
| 2, | |||||
| 6, | |||||
| 0, | |||||
| NULL, | |||||
| NULL); | |||||
| if (bvhtree == NULL) { | |||||
| return; | |||||
| } | |||||
| struct WeldOverlapData data; | |||||
| data.mvert = mvert; | |||||
| data.merge_dist_sq = square_f(wmd->merge_dist); | |||||
| *overlap = BLI_bvhtree_overlap_ex(bvhtree, | |||||
| bvhtree, | |||||
| overlap_len, | |||||
| bvhtree_weld_overlap_cb, | |||||
| &data, | |||||
| wmd->max_interactions, | |||||
| BVH_OVERLAP_RETURN_PAIRS); | |||||
| free_bvhtree_from_mesh(&treedata); | |||||
| } | |||||
| static void weld_vert_map_setup_full(WeldModifierData *wmd, | |||||
| BLI_bitmap *v_mask, | |||||
| uint v_mask_act, | |||||
| Mesh *mesh, | |||||
| uint *r_vert_dest_map, | uint *r_vert_dest_map, | ||||
| WeldVert **r_wvert, | |||||
| uint *r_wvert_len, | |||||
| uint *r_vert_kill_len) | uint *r_vert_kill_len) | ||||
| { | { | ||||
| range_vn_u(r_vert_dest_map, mvert_len, 0); | BVHTreeOverlap *overlap = NULL; | ||||
| uint overlap_len = 0; | |||||
| weld_bvh_find_overlaps(wmd, v_mask, v_mask_act, mesh, &overlap, &overlap_len); | |||||
| uint vert_kill_len = 0; | uint vert_kill_len = 0; | ||||
| const BVHTreeOverlap *overlap_iter = &overlap[0]; | const BVHTreeOverlap *overlap_iter = &overlap[0]; | ||||
| for (uint i = 0; i < overlap_len; i++, overlap_iter++) { | for (uint i = 0; i < overlap_len; i++, overlap_iter++) { | ||||
| uint indexA = overlap_iter->indexA; | uint indexA = overlap_iter->indexA; | ||||
| uint indexB = overlap_iter->indexB; | uint indexB = overlap_iter->indexB; | ||||
| BLI_assert(indexA < indexB); | BLI_assert(indexA < indexB); | ||||
| Show All 11 Lines | for (uint i = 0; i < overlap_len; i++, overlap_iter++) { | ||||
| } | } | ||||
| if (va_dst > vb_dst) { | if (va_dst > vb_dst) { | ||||
| SWAP(uint, va_dst, vb_dst); | SWAP(uint, va_dst, vb_dst); | ||||
| } | } | ||||
| vert_kill_len++; | vert_kill_len++; | ||||
| r_vert_dest_map[vb_dst] = va_dst; | r_vert_dest_map[vb_dst] = va_dst; | ||||
| } | } | ||||
| /* Fix #r_vert_dest_map for next step. */ | weld_fix_vert_map(r_vert_dest_map, mesh->totvert); | ||||
| for (uint i = 0; i < mvert_len; i++) { | |||||
| if (i == r_vert_dest_map[i]) { | #ifdef USE_WELD_DEBUG | ||||
| r_vert_dest_map[i] = OUT_OF_CONTEXT; | weld_assert_vert_dest_map_setup(overlap, overlap_len, r_vert_dest_map); | ||||
| #endif | |||||
| if (overlap != NULL) { | |||||
| MEM_freeN(overlap); | |||||
| } | |||||
| *r_vert_kill_len = vert_kill_len; | |||||
| } | |||||
| static void weld_vert_map_setup_simple(WeldModifierData *wmd, | |||||
| BLI_bitmap *v_mask, | |||||
| uint v_mask_act, | |||||
Done Inline ActionsRemove or change this unused parameter to uint UNUSED(v_mask_act). mano-wii: Remove or change this unused parameter to `uint UNUSED(v_mask_act)`.
This avoids warnings on… | |||||
| Mesh *mesh, | |||||
| uint *r_vert_dest_map, | |||||
| uint *r_vert_kill_len) | |||||
| { | |||||
| MVert *mvert; | |||||
| MEdge *medge, *me; | |||||
| uint totvert, totedge; | |||||
| medge = mesh->medge; | |||||
| totvert = mesh->totvert; | |||||
| totedge = mesh->totedge; | |||||
| uint vert_kill_len = 0; | |||||
| mvert = MEM_malloc_arrayN(totvert, sizeof(*mvert), __func__); | |||||
| memcpy(mvert, mesh->mvert, totvert * sizeof(*mvert)); | |||||
| float merge_dist_sq = square_f(wmd->merge_dist); | |||||
| uint *vert_dest_map = r_vert_dest_map; | |||||
| uint *combined_verts = MEM_calloc_arrayN(totvert, sizeof(*combined_verts), __func__); | |||||
| float edgedir[3]; | |||||
| /* Collapse Edges that are shorter than the threshold. */ | |||||
| me = &medge[0]; | |||||
| for (uint i = 0; i < totedge; i++, me++) { | |||||
| uint v1 = vert_dest_map[me->v1]; | |||||
| while (v1 != vert_dest_map[v1]) { | |||||
| v1 = vert_dest_map[v1]; | |||||
| } | |||||
| uint v2 = vert_dest_map[me->v2]; | |||||
| while (v2 != vert_dest_map[v2]) { | |||||
| v2 = vert_dest_map[v2]; | |||||
| } | |||||
| if (v1 == v2) { | |||||
| continue; | |||||
| } | |||||
| if (v_mask && (!BLI_BITMAP_TEST(v_mask, v1) || !BLI_BITMAP_TEST(v_mask, v2))) { | |||||
| continue; | continue; | ||||
| } | } | ||||
| if (v1 > v2) { | |||||
| SWAP(uint, v1, v2); | |||||
| } | |||||
| sub_v3_v3v3(edgedir, mvert[v2].co, mvert[v1].co); | |||||
| const float dist_sq = len_squared_v3(edgedir); | |||||
| if (dist_sq <= merge_dist_sq) { | |||||
| vert_kill_len++; | |||||
| uint v = i; | mul_v3_fl(edgedir, | ||||
Not Done Inline ActionsIs it really necessary to allocate these arrays mvert and combined_verts? Isn't the idea here just to detect the edges that collapse? mano-wii: Is it really necessary to allocate these arrays `mvert` and `combined_verts`?
Apparently the… | |||||
Done Inline ActionsThis came from complex solidify. Originally it didn't have that, but the chain merging was quite severe on meshes with ordered vertices like text. Honestly it is also quite bad with the usual weld modifier. D7224 changed that in solidify and I want to keep it like that. If you can think of a different way of getting rid of that chaining with a good result, propose it, but I found this (even though it is order dependend) is fairly good in practice and the order dependency does usually not become a problem (See T75032#896741 for the things I thought of how to solve this). Also the calculated positions could potentially be used as final positions in the future, removing some of the extra overhead. What I am more concerned with here is, that with very high merging thresholds various spikes appear. I know the reason for it, but it's not trivial to fix. weasel: This came from complex solidify. Originally it didn't have that, but the chain merging was… | |||||
| while (v != r_vert_dest_map[v] && r_vert_dest_map[v] != OUT_OF_CONTEXT) { | (combined_verts[v2] + 1) / (float)(combined_verts[v1] + combined_verts[v2] + 2)); | ||||
| v = r_vert_dest_map[v]; | add_v3_v3(mvert[v1].co, edgedir); | ||||
| combined_verts[v1] += combined_verts[v2] + 1; | |||||
| vert_dest_map[v2] = v1; | |||||
| } | } | ||||
| r_vert_dest_map[v] = v; | |||||
| r_vert_dest_map[i] = v; | |||||
| } | } | ||||
| MEM_freeN(combined_verts); | |||||
| MEM_freeN(mvert); | |||||
| weld_fix_vert_map(vert_dest_map, totvert); | |||||
| *r_vert_kill_len = vert_kill_len; | |||||
| } | |||||
| static void weld_vert_ctx_alloc_and_setup(const uint mvert_len, | |||||
| uint *r_vert_dest_map, | |||||
| WeldVert **r_wvert, | |||||
| uint *r_wvert_len) | |||||
| { | |||||
| /* 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, | 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__); | ||||
| r_weld_mesh->vert_kill_len = vert_kill_len; | |||||
| WeldVert *wvert; | WeldVert *wvert; | ||||
| uint wvert_len; | uint wvert_len; | ||||
| weld_vert_ctx_alloc_and_setup(mvert_len, | weld_vert_ctx_alloc_and_setup(mvert_len, vert_dest_map, &wvert, &wvert_len); | ||||
| overlap, | |||||
| 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 38 Lines | #endif | ||||
| 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); | |||||
Not Done Inline ActionsWhy was this line removed? mano-wii: Why was this line removed? | |||||
Done Inline ActionsAs weld_mesh should be setup in weld_mesh_context_create I removed vert_groups_map from it and made it an argument to the functions that need it. The problem is that this free will not be called if no vertices where merged, but the memory would still have been allocated. So I wanted both cases in one and put it at the bottom of doWeld. I think of vert_dest_map as the backbone of the whole modifier, because it is used all throughout. It should not be part of weld_mesh, which is only used for one (conditional) step of the modifier. weasel: As `weld_mesh` should be setup in `weld_mesh_context_create` I removed `vert_groups_map` from… | |||||
| 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 | ||||
| * \{ */ | * \{ */ | ||||
| struct WeldOverlapData { | |||||
| const MVert *mvert; | |||||
| float merge_dist_sq; | |||||
| }; | |||||
| static bool bvhtree_weld_overlap_cb(void *userdata, int index_a, int index_b, int UNUSED(thread)) | |||||
| { | |||||
| if (index_a < index_b) { | |||||
| struct WeldOverlapData *data = userdata; | |||||
| const MVert *mvert = data->mvert; | |||||
| 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)); | |||||
| return dist_sq <= data->merge_dist_sq; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| 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 20 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++; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Get overlap map. */ | if (v_mask && v_mask_act == 0) { | ||||
| /* TODO: For a better performanse use KD-Tree. */ | |||||
| struct BVHTreeFromMesh treedata; | |||||
| BVHTree *bvhtree = bvhtree_from_mesh_verts_ex(&treedata, | |||||
| mvert, | |||||
| totvert, | |||||
| false, | |||||
| v_mask, | |||||
| v_mask_act, | |||||
| wmd->merge_dist / 2, | |||||
| 2, | |||||
| 6, | |||||
| 0, | |||||
| NULL, | |||||
| NULL); | |||||
| if (v_mask) { | |||||
| MEM_freeN(v_mask); | MEM_freeN(v_mask); | ||||
| } | |||||
| if (bvhtree == NULL) { | |||||
| return result; | return result; | ||||
| } | } | ||||
| struct WeldOverlapData data; | uint *vert_dest_map = MEM_malloc_arrayN(totvert, sizeof(*vert_dest_map), __func__); | ||||
| data.mvert = mvert; | range_vn_u(vert_dest_map, totvert, 0); | ||||
| data.merge_dist_sq = square_f(wmd->merge_dist); | uint vert_kill_len = 0; | ||||
| uint overlap_len; | if (wmd->mode == MOD_WELD_SIMPLE_MODE) { | ||||
| BVHTreeOverlap *overlap = BLI_bvhtree_overlap_ex(bvhtree, | weld_vert_map_setup_simple(wmd, v_mask, v_mask_act, mesh, vert_dest_map, &vert_kill_len); | ||||
| bvhtree, | } | ||||
| &overlap_len, | else { | ||||
| bvhtree_weld_overlap_cb, | /* Assuming wmd->mode == MOD_WELD_FULL_MODE. */ | ||||
Done Inline ActionsHere instead of a comment, you can use a BLI_assert(MOD_WELD_ALL_MODE). mano-wii: Here instead of a comment, you can use a `BLI_assert(MOD_WELD_ALL_MODE)`.
Thus, in addition to… | |||||
| &data, | weld_vert_map_setup_full(wmd, v_mask, v_mask_act, mesh, vert_dest_map, &vert_kill_len); | ||||
| wmd->max_interactions, | } | ||||
| BVH_OVERLAP_RETURN_PAIRS); | |||||
| free_bvhtree_from_mesh(&treedata); | if (v_mask) { | ||||
| MEM_freeN(v_mask); | |||||
| } | |||||
| if (overlap_len) { | 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; | ||||
| ▲ Show 20 Lines • Show All 174 Lines • ▼ Show 20 Lines | if (vert_kill_len) { | ||||
| BLI_assert(loop_cur == result_nloops); | BLI_assert(loop_cur == result_nloops); | ||||
| /* 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); | ||||
| } | } | ||||
| if (vert_dest_map) { | |||||
| MEM_freeN(vert_dest_map); | |||||
| } | |||||
| MEM_freeN(overlap); | |||||
| 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->max_interactions = 1; | ||||
| wmd->mode = MOD_WELD_SIMPLE_MODE; | |||||
mano-wiiUnsubmitted Done Inline ActionsIt will probably be necessary to create a versioning (in ...\source\blender\blenloader\intern\versioning_290.c) to adapt old files. mano-wii: It will probably be necessary to create a versioning (in `... | |||||
weaselAuthorUnsubmitted Done Inline ActionsI dont think so. I made sure current "Full" Mode is mode=0 so when old files get loaded it will automatically choose Full (AFAIK and tested) weasel: I dont think so. I made sure current "Full" Mode is mode=0 so when old files get loaded it will… | |||||
| 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; | ||||
| /* Ask for vertexgroups if we need them. */ | /* Ask for vertexgroups if we need them. */ | ||||
| if (wmd->defgrp_name[0] != '\0') { | if (wmd->defgrp_name[0] != '\0') { | ||||
| r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; | r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; | ||||
| } | } | ||||
| } | } | ||||
| static void panel_draw(const bContext *UNUSED(C), Panel *panel) | 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); | ||||
| int mode = RNA_enum_get(ptr, "mode"); | |||||
| uiLayoutSetPropSep(layout, true); | uiLayoutSetPropSep(layout, true); | ||||
| uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE); | |||||
| uiItemR(layout, ptr, "merge_threshold", 0, IFACE_("Distance"), ICON_NONE); | uiItemR(layout, ptr, "merge_threshold", 0, IFACE_("Distance"), ICON_NONE); | ||||
| if (mode == MOD_WELD_FULL_MODE) { | |||||
| uiItemR(layout, ptr, "max_interactions", 0, NULL, 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 | |||||
I'm not sure if "weld_fix_vert_map" is an appropriate name
A comment here would be useful to explain what this function fixes.