diff options
author | Pablo Dobarro <pablodp606@gmail.com> | 2020-07-09 18:56:00 +0300 |
---|---|---|
committer | Pablo Dobarro <pablodp606@gmail.com> | 2020-07-09 18:56:56 +0300 |
commit | 6778949e0114ab4bb6c157c03948f86b13b73ea2 (patch) | |
tree | c244a817044283dd3a7760737423e1dd1ae6d0a1 /source | |
parent | 7b1c406b5431ce65d84ddb5f2c53977c25c18373 (diff) |
Fix repeated Face Sets IDs when joining meshes
As Face Sets IDs start from 0 and increase by 1 each time a new face set
is created in a mesh, when joining multiple meshes it could happen that
the same ID is used by several unrelated areas in multiple objects. This
checks the Face Sets IDs when joining meshes and ensures that they are
not repeated between different objects when joining them, so in the
resulting mesh all previous face sets will have different IDs.
Reviewed By: sergey
Differential Revision: https://developer.blender.org/D8224
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/editors/mesh/meshtools.c | 41 |
1 files changed, 40 insertions, 1 deletions
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index b0730b32bed..f759ec4d855 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -297,6 +297,37 @@ static void join_mesh_single(Depsgraph *depsgraph, *mpoly_pp += me->totpoly; } +/* Face Sets IDs are a sparse sequence, so this function offsets all the IDs by face_set_offset and + * updates face_set_offset with the maximum ID value. This way, when used in multiple meshes, all + * of them will have different IDs for their Face Sets. */ +static void mesh_join_offset_face_sets_ID(const Mesh *mesh, int *face_set_offset) +{ + if (!mesh->totpoly) { + return; + } + + int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS); + if (!face_sets) { + return; + } + + int max_face_set = 0; + for (int f = 0; f < mesh->totpoly; f++) { + /* As face sets enconde the visibility in the integer sign, the offset needs to be added or + * substracted depending on the initial sign of the integer to get the new ID. */ + if (abs(face_sets[f]) <= *face_set_offset) { + if (face_sets[f] > 0) { + face_sets[f] += *face_set_offset; + } + else { + face_sets[f] -= *face_set_offset; + } + } + max_face_set = max_ii(max_face_set, abs(face_sets[f])); + } + *face_set_offset = max_face_set; +} + int ED_mesh_join_objects_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); @@ -431,7 +462,13 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op) key->type = KEY_RELATIVE; } - /* First pass over objects: Copying materials, vertex-groups & face-maps across. */ + /* Update face_set_id_offset with the face set data in the active object first. This way the Face + * Sets IDs in the active object are not the ones that are modified. */ + Mesh *mesh_active = BKE_mesh_from_object(ob); + int face_set_id_offset = 0; + mesh_join_offset_face_sets_ID(mesh_active, &face_set_id_offset); + + /* Copy materials, vertex-groups, face sets & face-maps across objects. */ CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) { /* only act if a mesh, and not the one we're joining to */ if ((ob != ob_iter) && (ob_iter->type == OB_MESH)) { @@ -463,6 +500,8 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op) ob->actfmap = 1; } + mesh_join_offset_face_sets_ID(me, &face_set_id_offset); + if (me->totvert) { /* Add this object's materials to the base one's if they don't exist already * (but only if limits not exceeded yet) */ |