From d9d3ed16a8c61bb1c780d81a2cf398be92cd16c1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 6 Mar 2018 09:57:41 +1100 Subject: Fix T53206: Array modifier doesn't merge vgroups Vertex group remapping utility function, now shared between object join and array modifier cap-ends. Weights which don't exist are removed. D3092 by @Foaly --- source/blender/blenkernel/BKE_object_deform.h | 3 +- source/blender/blenkernel/intern/object_deform.c | 64 ++++++++++++++++++++++++ source/blender/editors/mesh/meshtools.c | 22 +++----- source/blender/modifiers/intern/MOD_array.c | 32 ++++++++++-- 4 files changed, 102 insertions(+), 19 deletions(-) diff --git a/source/blender/blenkernel/BKE_object_deform.h b/source/blender/blenkernel/BKE_object_deform.h index 19a2220006a..ab54330cf53 100644 --- a/source/blender/blenkernel/BKE_object_deform.h +++ b/source/blender/blenkernel/BKE_object_deform.h @@ -54,7 +54,8 @@ void BKE_object_defgroup_remove(struct Object *ob, struct bDeformGroup *defgroup void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked); void BKE_object_defgroup_remove_all(struct Object *ob); - +int *BKE_object_defgroup_index_map_create(struct Object *ob_src, struct Object *ob_dst, int *r_map_len); +void BKE_object_defgroup_index_map_apply(struct MDeformVert *dvert, int dvert_len, const int *map, int map_len); /* Select helpers */ enum eVGroupSelect; diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c index 2726064d634..61533e13d7a 100644 --- a/source/blender/blenkernel/intern/object_deform.c +++ b/source/blender/blenkernel/intern/object_deform.c @@ -457,6 +457,70 @@ void BKE_object_defgroup_remove_all(struct Object *ob) BKE_object_defgroup_remove_all_ex(ob, false); } +/** + * Compute mapping for vertex groups with matching name, -1 is used for no remapping. + * Returns null if no remapping is required. + * The returned array has to be freed. + */ +int *BKE_object_defgroup_index_map_create(Object *ob_src, Object *ob_dst, int *r_map_len) +{ + /* Build src to merged mapping of vgroup indices. */ + if (BLI_listbase_is_empty(&ob_src->defbase) || BLI_listbase_is_empty(&ob_dst->defbase)) { + *r_map_len = 0; + return NULL; + } + + bDeformGroup *dg_src; + *r_map_len = BLI_listbase_count(&ob_src->defbase); + int *vgroup_index_map = MEM_malloc_arrayN(*r_map_len, sizeof(*vgroup_index_map), "defgroup index map create"); + bool is_vgroup_remap_needed = false; + int i; + + for (dg_src = ob_src->defbase.first, i = 0; dg_src; dg_src = dg_src->next, i++) { + vgroup_index_map[i] = defgroup_name_index(ob_dst, dg_src->name); + is_vgroup_remap_needed = is_vgroup_remap_needed || (vgroup_index_map[i] != i); + } + + if (!is_vgroup_remap_needed) { + MEM_freeN(vgroup_index_map); + vgroup_index_map = NULL; + *r_map_len = 0; + } + + return vgroup_index_map; +} + +void BKE_object_defgroup_index_map_apply(MDeformVert *dvert, int dvert_len, const int *map, int map_len) +{ + if (map == NULL || map_len == 0) { + return; + } + + MDeformVert *dv = dvert; + for (int i = 0; i < dvert_len; i++, dv++) { + int totweight = dv->totweight; + for (int j = 0; j < totweight; j++) { + int def_nr = dv->dw[j].def_nr; + if ((uint)def_nr < (uint)map_len && map[def_nr] != -1) { + dv->dw[j].def_nr = map[def_nr]; + } + else { + totweight--; + dv->dw[j] = dv->dw[totweight]; + j--; + } + } + if (totweight != dv->totweight) { + if (totweight) { + dv->dw = MEM_reallocN(dv->dw, sizeof(*dv->dw) * totweight); + } + else { + MEM_SAFE_FREE(dv->dw); + } + dv->totweight = totweight; + } + } +} /** * Get MDeformVert vgroup data from given object. Should only be used in Object mode. diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index c900373a59c..fa1c935e2ff 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -58,6 +58,7 @@ #include "BKE_mesh.h" #include "BKE_material.h" #include "BKE_object.h" +#include "BKE_object_deform.h" #include "BKE_report.h" #include "BKE_editmesh.h" #include "BKE_multires.h" @@ -111,21 +112,12 @@ static void join_mesh_single( BLI_assert(dvert != NULL); /* Build src to merged mapping of vgroup indices. */ - bDeformGroup *dg_src; - int *vgroup_index_map = alloca(sizeof(*vgroup_index_map) * BLI_listbase_count(&ob_src->defbase)); - bool is_vgroup_remap_needed = false; - - for (dg_src = ob_src->defbase.first, b = 0; dg_src; dg_src = dg_src->next, b++) { - vgroup_index_map[b] = defgroup_name_index(ob_dst, dg_src->name); - is_vgroup_remap_needed = is_vgroup_remap_needed || (vgroup_index_map[b] != b); - } - - if (is_vgroup_remap_needed) { - for (a = 0; a < me->totvert; a++) { - for (b = 0; b < dvert[a].totweight; b++) { - dvert[a].dw[b].def_nr = vgroup_index_map[dvert_src[a].dw[b].def_nr]; - } - } + int *vgroup_index_map; + int vgroup_index_map_len; + vgroup_index_map = BKE_object_defgroup_index_map_create(ob_src, ob_dst, &vgroup_index_map_len); + BKE_object_defgroup_index_map_apply(dvert, me->totvert, vgroup_index_map, vgroup_index_map_len); + if (vgroup_index_map != NULL) { + MEM_freeN(vgroup_index_map); } } diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index 053957d89e2..b781c47ac56 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -51,6 +51,7 @@ #include "BKE_library_query.h" #include "BKE_modifier.h" #include "BKE_mesh.h" +#include "BKE_object_deform.h" #include "MOD_util.h" @@ -312,7 +313,7 @@ static void dm_mvert_map_doubles( static void dm_merge_transform( DerivedMesh *result, DerivedMesh *cap_dm, float cap_offset[4][4], unsigned int cap_verts_index, unsigned int cap_edges_index, int cap_loops_index, int cap_polys_index, - int cap_nverts, int cap_nedges, int cap_nloops, int cap_npolys) + int cap_nverts, int cap_nedges, int cap_nloops, int cap_npolys, int *remap, int remap_len) { int *index_orig; int i; @@ -320,6 +321,7 @@ static void dm_merge_transform( MEdge *me; MLoop *ml; MPoly *mp; + MDeformVert *dvert; /* needed for subsurf so arrays are allocated */ cap_dm->getVertArray(cap_dm); @@ -340,6 +342,12 @@ static void dm_merge_transform( mv->flag = mv->bweight = 0; } + /* remap the vertex groups if necessary */ + dvert = DM_get_vert_data(result, cap_verts_index, CD_MDEFORMVERT); + if (dvert != NULL) { + BKE_object_defgroup_index_map_apply(dvert, cap_nverts, remap, remap_len); + } + /* adjust cap edge vertex indices */ me = CDDM_get_edges(result) + cap_edges_index; for (i = 0; i < cap_nedges; i++, me++) { @@ -417,6 +425,11 @@ static DerivedMesh *arrayModifier_doArray( DerivedMesh *result, *start_cap_dm = NULL, *end_cap_dm = NULL; + int *vgroup_start_cap_remap = NULL; + int vgroup_start_cap_remap_len = 0; + int *vgroup_end_cap_remap = NULL; + int vgroup_end_cap_remap_len = 0; + chunk_nverts = dm->getNumVerts(dm); chunk_nedges = dm->getNumEdges(dm); chunk_nloops = dm->getNumLoops(dm); @@ -425,6 +438,8 @@ static DerivedMesh *arrayModifier_doArray( count = amd->count; if (amd->start_cap && amd->start_cap != ob && amd->start_cap->type == OB_MESH) { + vgroup_start_cap_remap = BKE_object_defgroup_index_map_create(amd->start_cap, ob, &vgroup_start_cap_remap_len); + start_cap_dm = get_dm_for_modifier(amd->start_cap, flag); if (start_cap_dm) { start_cap_nverts = start_cap_dm->getNumVerts(start_cap_dm); @@ -434,6 +449,8 @@ static DerivedMesh *arrayModifier_doArray( } } if (amd->end_cap && amd->end_cap != ob && amd->end_cap->type == OB_MESH) { + vgroup_end_cap_remap = BKE_object_defgroup_index_map_create(amd->end_cap, ob, &vgroup_end_cap_remap_len); + end_cap_dm = get_dm_for_modifier(amd->end_cap, flag); if (end_cap_dm) { end_cap_nverts = end_cap_dm->getNumVerts(end_cap_dm); @@ -696,7 +713,8 @@ static DerivedMesh *arrayModifier_doArray( result_nedges - start_cap_nedges - end_cap_nedges, result_nloops - start_cap_nloops - end_cap_nloops, result_npolys - start_cap_npolys - end_cap_npolys, - start_cap_nverts, start_cap_nedges, start_cap_nloops, start_cap_npolys); + start_cap_nverts, start_cap_nedges, start_cap_nloops, start_cap_npolys, + vgroup_start_cap_remap, vgroup_start_cap_remap_len); /* Identify doubles with first chunk */ if (use_merge) { dm_mvert_map_doubles( @@ -720,7 +738,8 @@ static DerivedMesh *arrayModifier_doArray( result_nedges - end_cap_nedges, result_nloops - end_cap_nloops, result_npolys - end_cap_npolys, - end_cap_nverts, end_cap_nedges, end_cap_nloops, end_cap_npolys); + end_cap_nverts, end_cap_nedges, end_cap_nloops, end_cap_npolys, + vgroup_end_cap_remap, vgroup_end_cap_remap_len); /* Identify doubles with last chunk */ if (use_merge) { dm_mvert_map_doubles( @@ -768,6 +787,13 @@ static DerivedMesh *arrayModifier_doArray( result->dirty |= DM_DIRTY_NORMALS; } + if (vgroup_start_cap_remap) { + MEM_freeN(vgroup_start_cap_remap); + } + if (vgroup_end_cap_remap) { + MEM_freeN(vgroup_end_cap_remap); + } + return result; } -- cgit v1.2.3