From 3b26b46631eefe5a38b54c6465dc5dd82f2c6294 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 20 Jul 2012 10:33:15 +0000 Subject: Separate meshes by loose parts and materials now works in object mode as well as editmode. --- source/blender/editors/mesh/editmesh_tools.c | 165 ++++++++++++++++----------- 1 file changed, 98 insertions(+), 67 deletions(-) (limited to 'source/blender/editors/mesh') diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 5657cef4fd2..53744a01b8c 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -2790,121 +2790,110 @@ void MESH_OT_knife_cut(wmOperatorType *ot) RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX); } -static int mesh_separate_selected(Main *bmain, Scene *scene, Base *editbase, wmOperator *wmop) +static int mesh_separate_selected(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old) { - Base *basenew; + Base *base_new; BMIter iter; BMVert *v; BMEdge *e; - Object *obedit = editbase->object; - Mesh *me = obedit->data; - BMEditMesh *em = me->edit_btmesh; + Object *obedit = base_old->object; BMesh *bm_new; - - if (!em) - return FALSE; - + bm_new = BM_mesh_create(&bm_mesh_allocsize_default); - CustomData_copy(&em->bm->vdata, &bm_new->vdata, CD_MASK_BMESH, CD_CALLOC, 0); - CustomData_copy(&em->bm->edata, &bm_new->edata, CD_MASK_BMESH, CD_CALLOC, 0); - CustomData_copy(&em->bm->ldata, &bm_new->ldata, CD_MASK_BMESH, CD_CALLOC, 0); - CustomData_copy(&em->bm->pdata, &bm_new->pdata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&bm_old->vdata, &bm_new->vdata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&bm_old->edata, &bm_new->edata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&bm_old->ldata, &bm_new->ldata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&bm_old->pdata, &bm_new->pdata, CD_MASK_BMESH, CD_CALLOC, 0); CustomData_bmesh_init_pool(&bm_new->vdata, bm_mesh_allocsize_default.totvert, BM_VERT); CustomData_bmesh_init_pool(&bm_new->edata, bm_mesh_allocsize_default.totedge, BM_EDGE); CustomData_bmesh_init_pool(&bm_new->ldata, bm_mesh_allocsize_default.totloop, BM_LOOP); CustomData_bmesh_init_pool(&bm_new->pdata, bm_mesh_allocsize_default.totface, BM_FACE); - - basenew = ED_object_add_duplicate(bmain, scene, editbase, USER_DUP_MESH); + + base_new = ED_object_add_duplicate(bmain, scene, base_old, USER_DUP_MESH); /* DAG_scene_sort(bmain, scene); */ /* normally would call directly after but in this case delay recalc */ - assign_matarar(basenew->object, give_matarar(obedit), *give_totcolp(obedit)); /* new in 2.5 */ + assign_matarar(base_new->object, give_matarar(obedit), *give_totcolp(obedit)); /* new in 2.5 */ - ED_base_object_select(basenew, BA_DESELECT); - - EDBM_op_callf(em, wmop, "duplicate geom=%hvef dest=%p", BM_ELEM_SELECT, bm_new); - EDBM_op_callf(em, wmop, "delete geom=%hvef context=%i", BM_ELEM_SELECT, DEL_FACES); + ED_base_object_select(base_new, BA_SELECT); + + BMO_op_callf(bm_old, "duplicate geom=%hvef dest=%p", BM_ELEM_SELECT, bm_new); + BMO_op_callf(bm_old, "delete geom=%hvef context=%i", BM_ELEM_SELECT, DEL_FACES); /* clean up any loose edges */ - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + BM_ITER_MESH (e, &iter, bm_old, BM_EDGES_OF_MESH) { if (BM_elem_flag_test(e, BM_ELEM_HIDDEN)) continue; if (!BM_edge_is_wire(e)) { - BM_edge_select_set(em->bm, e, FALSE); + BM_edge_select_set(bm_old, e, FALSE); } } - EDBM_op_callf(em, wmop, "delete geom=%hvef context=%i", BM_ELEM_SELECT, DEL_EDGES); + BMO_op_callf(bm_old, "delete geom=%hvef context=%i", BM_ELEM_SELECT, DEL_EDGES); /* clean up any loose verts */ - BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { + BM_ITER_MESH (v, &iter, bm_old, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v, BM_ELEM_HIDDEN)) continue; if (BM_vert_edge_count(v) != 0) { - BM_vert_select_set(em->bm, v, FALSE); + BM_vert_select_set(bm_old, v, FALSE); } } - EDBM_op_callf(em, wmop, "delete geom=%hvef context=%i", BM_ELEM_SELECT, DEL_VERTS); + BMO_op_callf(bm_old, "delete geom=%hvef context=%i", BM_ELEM_SELECT, DEL_VERTS); BM_mesh_normals_update(bm_new, TRUE); - BM_mesh_bm_to_me(bm_new, basenew->object->data, FALSE); - + BM_mesh_bm_to_me(bm_new, base_new->object->data, FALSE); + BM_mesh_free(bm_new); - ((Mesh *)basenew->object->data)->edit_btmesh = NULL; + ((Mesh *)base_new->object->data)->edit_btmesh = NULL; return TRUE; } -static int mesh_separate_material(Main *bmain, Scene *scene, Base *editbase, wmOperator *wmop) +static int mesh_separate_material(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old) { BMFace *f_cmp, *f; BMIter iter; int result = FALSE; - Object *obedit = editbase->object; - BMEditMesh *em = BMEdit_FromObject(obedit); - BMesh *bm = em->bm; - EDBM_flag_disable_all(em, BM_ELEM_SELECT); + BM_mesh_elem_hflag_disable_all(bm_old, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, FALSE); - while ((f_cmp = BM_iter_at_index(bm, BM_FACES_OF_MESH, NULL, 0))) { + while ((f_cmp = BM_iter_at_index(bm_old, BM_FACES_OF_MESH, NULL, 0))) { const short mat_nr = f_cmp->mat_nr; int tot = 0; - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + BM_ITER_MESH (f, &iter, bm_old, BM_FACES_OF_MESH) { if (f->mat_nr == mat_nr) { - BM_face_select_set(bm, f, TRUE); + BM_face_select_set(bm_old, f, TRUE); tot++; } } /* leave the current object with some materials */ - if (tot == bm->totface) { + if (tot == bm_old->totface) { break; } /* Move selection into a separate object */ - result |= mesh_separate_selected(bmain, scene, editbase, wmop); + result |= mesh_separate_selected(bmain, scene, base_old, bm_old); } return result; } -static int mesh_separate_loose(Main *bmain, Scene *scene, Base *editbase, wmOperator *wmop) +static int mesh_separate_loose(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old) { int i; BMEdge *e; BMVert *v_seed; BMWalker walker; int result = FALSE; - Object *obedit = editbase->object; - BMEditMesh *em = BMEdit_FromObject(obedit); - BMesh *bm = em->bm; - int max_iter = bm->totvert; + int max_iter = bm_old->totvert; /* Clear all selected vertices */ - EDBM_flag_disable_all(em, BM_ELEM_SELECT); + BM_mesh_elem_hflag_disable_all(bm_old, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, FALSE); /* A "while (true)" loop should work here as each iteration should * select and remove at least one vertex and when all vertices @@ -2913,7 +2902,7 @@ static int mesh_separate_loose(Main *bmain, Scene *scene, Base *editbase, wmOper * original mesh.*/ for (i = 0; i < max_iter; i++) { /* Get a seed vertex to start the walk */ - v_seed = BM_iter_at_index(bm, BM_VERTS_OF_MESH, NULL, 0); + v_seed = BM_iter_at_index(bm_old, BM_VERTS_OF_MESH, NULL, 0); /* No vertices available, can't do anything */ if (v_seed == NULL) { @@ -2921,33 +2910,33 @@ static int mesh_separate_loose(Main *bmain, Scene *scene, Base *editbase, wmOper } /* Select the seed explicitly, in case it has no edges */ - BM_vert_select_set(bm, v_seed, TRUE); + BM_vert_select_set(bm_old, v_seed, TRUE); /* Walk from the single vertex, selecting everything connected * to it */ - BMW_init(&walker, bm, BMW_SHELL, + BMW_init(&walker, bm_old, BMW_SHELL, BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, BMW_FLAG_NOP, /* BMESH_TODO - should be BMW_FLAG_TEST_HIDDEN ? */ BMW_NIL_LAY); e = BMW_begin(&walker, v_seed); for (; e; e = BMW_step(&walker)) { - BM_vert_select_set(bm, e->v1, TRUE); - BM_vert_select_set(bm, e->v2, TRUE); + BM_vert_select_set(bm_old, e->v1, TRUE); + BM_vert_select_set(bm_old, e->v2, TRUE); } BMW_end(&walker); - + /* Flush the selection to get edge/face selections matching * the vertex selection */ - EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX); + BM_mesh_select_mode_flush_ex(bm_old, SCE_SELECT_VERTEX); - if (bm->totvert == bm->totvertsel) { + if (bm_old->totvert == bm_old->totvertsel) { /* Every vertex selected, nothing to separate, work is done */ break; } /* Move selection into a separate object */ - result |= mesh_separate_selected(bmain, scene, editbase, wmop); + result |= mesh_separate_selected(bmain, scene, base_old, bm_old); } return result; @@ -2957,24 +2946,66 @@ static int edbm_separate_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Base *base = CTX_data_active_base(C); int retval = 0, type = RNA_enum_get(op->ptr, "type"); - if (type == 0) - retval = mesh_separate_selected(bmain, scene, base, op); - else if (type == 1) - retval = mesh_separate_material(bmain, scene, base, op); - else if (type == 2) - retval = mesh_separate_loose(bmain, scene, base, op); - - if (retval) { + if (ED_operator_editmesh(C)) { + Base *base = CTX_data_active_base(C); BMEditMesh *em = BMEdit_FromObject(base->object); + /* editmode separate */ + if (type == 0) retval = mesh_separate_selected(bmain, scene, base, em->bm); + else if (type == 1) retval = mesh_separate_material(bmain, scene, base, em->bm); + else if (type == 2) retval = mesh_separate_loose(bmain, scene, base, em->bm); + else BLI_assert(0); + + if (retval) { + EDBM_update_generic(C, em, TRUE); + } + } + else { + if (type == 0) { + BKE_report(op->reports, RPT_ERROR, "Selecton not supported in object mode"); + return OPERATOR_CANCELLED; + } + + /* object mode separate */ + CTX_DATA_BEGIN(C, Base *, base_iter, selected_editable_bases) + { + Object *ob = base_iter->object; + if (ob->type == OB_MESH) { + Mesh *me = ob->data; + if (me->id.lib == NULL) { + BMesh *bm_old = NULL; + int retval_iter = 0; + + bm_old = BM_mesh_create(&bm_mesh_allocsize_default); + + BM_mesh_bm_from_me(bm_old, me, FALSE, 0); + + if (type == 1) retval_iter = mesh_separate_material(bmain, scene, base_iter, bm_old); + else if (type == 2) retval_iter = mesh_separate_loose(bmain, scene, base_iter, bm_old); + else BLI_assert(0); + + if (retval_iter) { + BM_mesh_bm_to_me(bm_old, me, FALSE); + + DAG_id_tag_update(&me->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); + } + + BM_mesh_free(bm_old); + + retval |= retval_iter; + } + } + } + CTX_DATA_END; + } + + if (retval) { /* delay depsgraph recalc until all objects are duplicated */ DAG_scene_sort(bmain, scene); - EDBM_update_generic(C, em, TRUE); - return OPERATOR_FINISHED; } @@ -3000,7 +3031,7 @@ void MESH_OT_separate(wmOperatorType *ot) /* api callbacks */ ot->invoke = WM_menu_invoke; ot->exec = edbm_separate_exec; - ot->poll = ED_operator_editmesh; + ot->poll = ED_operator_scene_editable; /* object and editmode */ /* flags */ ot->flag = OPTYPE_UNDO; @@ -5106,7 +5137,7 @@ static int edbm_convex_hull_exec(bContext *C, wmOperator *op) Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BMEdit_FromObject(obedit); BMOperator bmop; - + EDBM_op_init(em, &bmop, op, "convex_hull input=%hvef " "use_existing_faces=%b", BM_ELEM_SELECT, -- cgit v1.2.3