diff options
Diffstat (limited to 'source/blender/modifiers/intern/MOD_boolean.cc')
-rw-r--r-- | source/blender/modifiers/intern/MOD_boolean.cc | 116 |
1 files changed, 72 insertions, 44 deletions
diff --git a/source/blender/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc index d47f2a130e3..aa64c1f83bc 100644 --- a/source/blender/modifiers/intern/MOD_boolean.cc +++ b/source/blender/modifiers/intern/MOD_boolean.cc @@ -14,6 +14,7 @@ #include "BLI_math_geom.h" #include "BLI_math_matrix.h" #include "BLI_vector.hh" +#include "BLI_vector_set.hh" #include "BLT_translation.h" @@ -62,7 +63,11 @@ using blender::Array; using blender::float4x4; +using blender::IndexRange; +using blender::MutableSpan; +using blender::Span; using blender::Vector; +using blender::VectorSet; static void initData(ModifierData *md) { @@ -146,7 +151,7 @@ static Mesh *get_quick_mesh( mul_m4_v3(omat, mv->co); } - BKE_mesh_normals_tag_dirty(result); + BKE_mesh_tag_coords_changed(result); } break; @@ -223,7 +228,7 @@ static BMesh *BMD_mesh_bm_create( Mesh *mesh, Object *object, Mesh *mesh_operand_ob, Object *operand_ob, bool *r_is_flip) { #ifdef DEBUG_TIME - SCOPED_TIMER(__func__) + SCOPED_TIMER(__func__); #endif *r_is_flip = (is_negative_m4(object->obmat) != is_negative_m4(operand_ob->obmat)); @@ -270,7 +275,7 @@ static void BMD_mesh_intersection(BMesh *bm, bool is_flip) { #ifdef DEBUG_TIME - SCOPED_TIMER(__func__) + SCOPED_TIMER(__func__); #endif BooleanModifierData *bmd = (BooleanModifierData *)md; @@ -375,19 +380,23 @@ static void BMD_mesh_intersection(BMesh *bm, #ifdef WITH_GMP -/* Get a mapping from material slot numbers in the src_ob to slot numbers in the dst_ob. - * If a material doesn't exist in the dst_ob, the mapping just goes to the same slot - * or to zero if there aren't enough slots in the destination. - * Caller owns the returned array. */ -static Array<short> get_material_remap(Object *dest_ob, Object *src_ob) +/* Get a mapping from material slot numbers in the source geometry to slot numbers in the result + * geometry. The material is added to the result geometry if it doesn't already use it. */ +static Array<short> get_material_remap(Object &object, + const Mesh &mesh, + VectorSet<Material *> &materials) { - int n = src_ob->totcol; - if (n <= 0) { - n = 1; + const int material_num = mesh.totcol; + if (material_num == 0) { + /* Necessary for faces using the default material when there are no material slots. */ + return Array<short>({materials.index_of_or_add(nullptr)}); } - Array<short> remap(n); - BKE_object_material_remap_calc(dest_ob, src_ob, remap.data()); - return remap; + Array<short> map(material_num); + for (const int i : IndexRange(material_num)) { + Material *material = BKE_object_material_get_eval(&object, i + 1); + map[i] = materials.index_of_or_add(material); + } + return map; } static Mesh *exact_boolean_mesh(BooleanModifierData *bmd, @@ -396,10 +405,12 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd, { Vector<const Mesh *> meshes; Vector<float4x4 *> obmats; + + VectorSet<Material *> materials; Vector<Array<short>> material_remaps; # ifdef DEBUG_TIME - SCOPED_TIMER(__func__) + SCOPED_TIMER(__func__); # endif if ((bmd->flag & eBooleanModifierFlag_Object) && bmd->object == nullptr) { @@ -409,15 +420,23 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd, meshes.append(mesh); obmats.append((float4x4 *)&ctx->object->obmat); material_remaps.append({}); + if (mesh->totcol == 0) { + /* Necessary for faces using the default material when there are no material slots. */ + materials.add(nullptr); + } + else { + materials.add_multiple({mesh->mat, mesh->totcol}); + } + if (bmd->flag & eBooleanModifierFlag_Object) { - Mesh *mesh_operand = BKE_modifier_get_evaluated_mesh_from_evaluated_object(bmd->object, false); + Mesh *mesh_operand = BKE_modifier_get_evaluated_mesh_from_evaluated_object(bmd->object); if (!mesh_operand) { return mesh; } BKE_mesh_wrapper_ensure_mdata(mesh_operand); meshes.append(mesh_operand); obmats.append((float4x4 *)&bmd->object->obmat); - material_remaps.append(get_material_remap(ctx->object, bmd->object)); + material_remaps.append(get_material_remap(*bmd->object, *mesh_operand, materials)); } else if (bmd->flag & eBooleanModifierFlag_Collection) { Collection *collection = bmd->collection; @@ -425,14 +444,14 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd, if (collection) { FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, ob) { if (ob->type == OB_MESH && ob != ctx->object) { - Mesh *collection_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob, false); + Mesh *collection_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob); if (!collection_mesh) { continue; } BKE_mesh_wrapper_ensure_mdata(collection_mesh); meshes.append(collection_mesh); obmats.append((float4x4 *)&ob->obmat); - material_remaps.append(get_material_remap(ctx->object, ob)); + material_remaps.append(get_material_remap(*ob, *collection_mesh, materials)); } } FOREACH_COLLECTION_OBJECT_RECURSIVE_END; @@ -441,13 +460,19 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd, const bool use_self = (bmd->flag & eBooleanModifierFlag_Self) != 0; const bool hole_tolerant = (bmd->flag & eBooleanModifierFlag_HoleTolerant) != 0; - return blender::meshintersect::direct_mesh_boolean(meshes, - obmats, - *(float4x4 *)&ctx->object->obmat, - material_remaps, - use_self, - hole_tolerant, - bmd->operation); + Mesh *result = blender::meshintersect::direct_mesh_boolean(meshes, + obmats, + *(float4x4 *)&ctx->object->obmat, + material_remaps, + use_self, + hole_tolerant, + bmd->operation, + nullptr); + MEM_SAFE_FREE(result->mat); + result->mat = (Material **)MEM_malloc_arrayN(materials.size(), sizeof(Material *), __func__); + result->totcol = materials.size(); + MutableSpan(result->mat, result->totcol).copy_from(materials); + return result; } #endif @@ -470,7 +495,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * #endif #ifdef DEBUG_TIME - SCOPED_TIMER(__func__) + SCOPED_TIMER(__func__); #endif if (bmd->flag & eBooleanModifierFlag_Object) { @@ -480,8 +505,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * Object *operand_ob = bmd->object; - Mesh *mesh_operand_ob = BKE_modifier_get_evaluated_mesh_from_evaluated_object(operand_ob, - false); + Mesh *mesh_operand_ob = BKE_modifier_get_evaluated_mesh_from_evaluated_object(operand_ob); if (mesh_operand_ob) { /* XXX This is utterly non-optimal, we may go from a bmesh to a mesh back to a bmesh! @@ -515,27 +539,31 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, operand_ob) { if (operand_ob->type == OB_MESH && operand_ob != ctx->object) { - Mesh *mesh_operand_ob = BKE_modifier_get_evaluated_mesh_from_evaluated_object(operand_ob, - false); + Mesh *mesh_operand_ob = BKE_modifier_get_evaluated_mesh_from_evaluated_object(operand_ob); - if (mesh_operand_ob) { - /* XXX This is utterly non-optimal, we may go from a bmesh to a mesh back to a bmesh! - * But for 2.90 better not try to be smart here. */ - BKE_mesh_wrapper_ensure_mdata(mesh_operand_ob); + if (mesh_operand_ob == nullptr) { + continue; + } - bool is_flip; - BMesh *bm = BMD_mesh_bm_create(mesh, object, mesh_operand_ob, operand_ob, &is_flip); + /* XXX This is utterly non-optimal, we may go from a bmesh to a mesh back to a bmesh! + * But for 2.90 better not try to be smart here. */ + BKE_mesh_wrapper_ensure_mdata(mesh_operand_ob); - BMD_mesh_intersection(bm, md, ctx, mesh_operand_ob, object, operand_ob, is_flip); + bool is_flip; + BMesh *bm = BMD_mesh_bm_create(result, object, mesh_operand_ob, operand_ob, &is_flip); - /* Needed for multiple objects to work. */ - BMeshToMeshParams bmesh_to_mesh_params{}; - bmesh_to_mesh_params.calc_object_remap = false; - BM_mesh_bm_to_me(nullptr, bm, mesh, &bmesh_to_mesh_params); + BMD_mesh_intersection(bm, md, ctx, mesh_operand_ob, object, operand_ob, is_flip); + /* Needed for multiple objects to work. */ + if (result == mesh) { result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh); - BM_mesh_free(bm); } + else { + BMeshToMeshParams bmesh_to_mesh_params{}; + bmesh_to_mesh_params.calc_object_remap = false; + BM_mesh_bm_to_me(nullptr, bm, result, &bmesh_to_mesh_params); + } + BM_mesh_free(bm); } } FOREACH_COLLECTION_OBJECT_RECURSIVE_END; @@ -609,7 +637,7 @@ static void panelRegister(ARegionType *region_type) } ModifierTypeInfo modifierType_Boolean = { - /* name */ "Boolean", + /* name */ N_("Boolean"), /* structName */ "BooleanModifierData", /* structSize */ sizeof(BooleanModifierData), /* srna */ &RNA_BooleanModifier, |