diff options
Diffstat (limited to 'source/blender/editors/mesh/editmesh_tools.c')
-rw-r--r-- | source/blender/editors/mesh/editmesh_tools.c | 353 |
1 files changed, 315 insertions, 38 deletions
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 20c7f4eb521..93ebbbcf620 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -90,9 +90,9 @@ static int edbm_subdivide_exec(bContext *C, wmOperator *op) const float along_normal = RNA_float_get(op->ptr, "fractal_along_normal"); if (RNA_boolean_get(op->ptr, "quadtri") && - RNA_enum_get(op->ptr, "quadcorner") == SUBD_STRAIGHT_CUT) + RNA_enum_get(op->ptr, "quadcorner") == SUBD_CORNER_STRAIGHT_CUT) { - RNA_enum_set(op->ptr, "quadcorner", SUBD_INNERVERT); + RNA_enum_set(op->ptr, "quadcorner", SUBD_CORNER_INNERVERT); } BM_mesh_esubdivide(em->bm, BM_ELEM_SELECT, @@ -110,10 +110,10 @@ static int edbm_subdivide_exec(bContext *C, wmOperator *op) /* Note, these values must match delete_mesh() event values */ static EnumPropertyItem prop_mesh_cornervert_types[] = { - {SUBD_INNERVERT, "INNERVERT", 0, "Inner Vert", ""}, - {SUBD_PATH, "PATH", 0, "Path", ""}, - {SUBD_STRAIGHT_CUT, "STRAIGHT_CUT", 0, "Straight Cut", ""}, - {SUBD_FAN, "FAN", 0, "Fan", ""}, + {SUBD_CORNER_INNERVERT, "INNERVERT", 0, "Inner Vert", ""}, + {SUBD_CORNER_PATH, "PATH", 0, "Path", ""}, + {SUBD_CORNER_STRAIGHT_CUT, "STRAIGHT_CUT", 0, "Straight Cut", ""}, + {SUBD_CORNER_FAN, "FAN", 0, "Fan", ""}, {0, NULL, 0, NULL, NULL} }; @@ -141,7 +141,7 @@ void MESH_OT_subdivide(wmOperatorType *ot) RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, FLT_MAX, "Smoothness", "Smoothness factor", 0.0f, 1.0f); RNA_def_boolean(ot->srna, "quadtri", 0, "Quad/Tri Mode", "Tries to prevent ngons"); - RNA_def_enum(ot->srna, "quadcorner", prop_mesh_cornervert_types, SUBD_STRAIGHT_CUT, + RNA_def_enum(ot->srna, "quadcorner", prop_mesh_cornervert_types, SUBD_CORNER_STRAIGHT_CUT, "Quad Corner Type", "How to subdivide quad corners (anything other than Straight Cut will prevent ngons)"); RNA_def_float(ot->srna, "fractal", 0.0f, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor", 0.0f, 1000.0f); @@ -877,23 +877,49 @@ static int edbm_vert_connect_exec(bContext *C, wmOperator *op) BMEditMesh *em = BKE_editmesh_from_object(obedit); BMesh *bm = em->bm; BMOperator bmop; - const bool is_pair = (bm->totvertsel == 2); - int len; - + bool is_pair = (bm->totvertsel == 2); + int len = 0; + bool check_degenerate = true; + const int verts_len = bm->totvertsel; + BMVert **verts; + + verts = MEM_mallocN(sizeof(*verts) * verts_len, __func__); + { + BMIter iter; + BMVert *v; + int i = 0; + + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { + verts[i++] = v; + } + } + + if (is_pair) { + if (BM_vert_pair_share_face_check_cb( + verts[0], verts[1], + BM_elem_cb_check_hflag_disabled_simple(BMFace *, BM_ELEM_HIDDEN))) + { + check_degenerate = false; + is_pair = false; + } + } + } + if (is_pair) { if (!EDBM_op_init(em, &bmop, op, - "connect_vert_pair verts=%hv verts_exclude=%hv faces_exclude=%hf", - BM_ELEM_SELECT, BM_ELEM_HIDDEN, BM_ELEM_HIDDEN)) + "connect_vert_pair verts=%eb verts_exclude=%hv faces_exclude=%hf", + verts, verts_len, BM_ELEM_HIDDEN, BM_ELEM_HIDDEN)) { - return OPERATOR_CANCELLED; + goto finally; } } else { if (!EDBM_op_init(em, &bmop, op, - "connect_verts verts=%hv faces_exclude=%hf check_degenerate=%b", - BM_ELEM_SELECT, BM_ELEM_HIDDEN, true)) + "connect_verts verts=%eb faces_exclude=%hf check_degenerate=%b", + verts, verts_len, BM_ELEM_HIDDEN, check_degenerate)) { - return OPERATOR_CANCELLED; + goto finally; } } @@ -908,15 +934,18 @@ static int edbm_vert_connect_exec(bContext *C, wmOperator *op) } if (!EDBM_op_finish(em, &bmop, op, true)) { - return OPERATOR_CANCELLED; + len = 0; } else { EDBM_selectmode_flush(em); /* so newly created edges get the selection state from the vertex */ EDBM_update_generic(em, true, true); - - return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } + + +finally: + MEM_freeN(verts); + return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } void MESH_OT_vert_connect(wmOperatorType *ot) @@ -924,7 +953,7 @@ void MESH_OT_vert_connect(wmOperatorType *ot) /* identifiers */ ot->name = "Vertex Connect"; ot->idname = "MESH_OT_vert_connect"; - ot->description = "Connect 2 vertices of a face by an edge, splitting the face in two"; + ot->description = "Connect selected vertices of faces, splitting the face"; /* api callbacks */ ot->exec = edbm_vert_connect_exec; @@ -935,6 +964,225 @@ void MESH_OT_vert_connect(wmOperatorType *ot) } +/** + * check that endpoints are verts and only have a single selected edge connected. + */ +static bool bm_vert_is_select_history_open(BMesh *bm) +{ + BMEditSelection *ele_a = bm->selected.first; + BMEditSelection *ele_b = bm->selected.last; + if ((ele_a->htype == BM_VERT) && + (ele_b->htype == BM_VERT)) + { + if ((BM_iter_elem_count_flag(BM_EDGES_OF_VERT, (BMVert *)ele_a->ele, BM_ELEM_SELECT, true) == 1) && + (BM_iter_elem_count_flag(BM_EDGES_OF_VERT, (BMVert *)ele_b->ele, BM_ELEM_SELECT, true) == 1)) + { + return true; + } + } + + return false; +} + +static bool bm_vert_connect_pair(BMesh *bm, BMVert *v_a, BMVert *v_b) +{ + BMOperator bmop; + BMVert **verts; + const int totedge_orig = bm->totedge; + + BMO_op_init(bm, &bmop, BMO_FLAG_DEFAULTS, "connect_vert_pair"); + + verts = BMO_slot_buffer_alloc(&bmop, bmop.slots_in, "verts", 2); + verts[0] = v_a; + verts[1] = v_b; + + BM_vert_normal_update(verts[0]); + BM_vert_normal_update(verts[1]); + + BMO_op_exec(bm, &bmop); + BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true); + BMO_op_finish(bm, &bmop); + return (bm->totedge != totedge_orig); +} + +static bool bm_vert_connect_select_history(BMesh *bm) +{ + /* Logic is as follows: + * + * - If there are any isolated/wire verts - connect as edges. + * - Otherwise connect faces. + * - If all edges have been created already, closed the loop. + */ + if (BLI_listbase_count_ex(&bm->selected, 2) == 2 && (bm->totvertsel > 2)) { + BMEditSelection *ese; + int tot = 0; + bool changed = false; + bool has_wire = false; + // bool all_verts; + + /* ensure all verts have history */ + for (ese = bm->selected.first; ese; ese = ese->next, tot++) { + BMVert *v; + if (ese->htype != BM_VERT) { + break; + } + v = (BMVert *)ese->ele; + if ((has_wire == false) && ((v->e == NULL) || BM_vert_is_wire(v))) { + has_wire = true; + } + } + // all_verts = (ese == NULL); + + if (has_wire == false) { + /* all verts have faces , connect verts via faces! */ + if (tot == bm->totvertsel) { + BMEditSelection *ese_last; + ese_last = bm->selected.first; + ese = ese_last->next; + + do { + + if (BM_edge_exists((BMVert *)ese_last->ele, (BMVert *)ese->ele)) { + /* pass, edge exists (and will be selected) */ + } + else { + changed |= bm_vert_connect_pair(bm, (BMVert *)ese_last->ele, (BMVert *)ese->ele); + } + } while ((ese_last = ese), + (ese = ese->next)); + + if (changed) { + return true; + } + } + + if (changed == false) { + /* existing loops: close the selection */ + if (bm_vert_is_select_history_open(bm)) { + changed |= bm_vert_connect_pair( + bm, + (BMVert *)((BMEditSelection *)bm->selected.first)->ele, + (BMVert *)((BMEditSelection *)bm->selected.last)->ele); + + if (changed) { + return true; + } + } + } + } + + else { + /* no faces, simply connect the verts by edges */ + BMEditSelection *ese_prev; + ese_prev = bm->selected.first; + ese = ese_prev->next; + + + do { + if (BM_edge_exists((BMVert *)ese_prev->ele, (BMVert *)ese->ele)) { + /* pass, edge exists (and will be selected) */ + } + else { + BMEdge *e; + e = BM_edge_create(bm, (BMVert *)ese_prev->ele, (BMVert *)ese->ele, NULL, 0); + BM_edge_select_set(bm, e, true); + changed = true; + } + } while ((ese_prev = ese), + (ese = ese->next)); + + if (changed == false) { + /* existing loops: close the selection */ + if (bm_vert_is_select_history_open(bm)) { + BMEdge *e; + ese_prev = bm->selected.first; + ese = bm->selected.last; + e = BM_edge_create(bm, (BMVert *)ese_prev->ele, (BMVert *)ese->ele, NULL, 0); + BM_edge_select_set(bm, e, true); + } + } + + return true; + } + } + + return false; +} + + +static int edbm_vert_connect_path_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + bool is_pair = (em->bm->totvertsel == 2); + + /* when there is only 2 vertices, we can ignore selection order */ + if (is_pair) { + return edbm_vert_connect_exec(C, op); + } + + if (bm_vert_connect_select_history(em->bm)) { + EDBM_selectmode_flush(em); + EDBM_update_generic(em, true, true); + + return OPERATOR_FINISHED; + } + else { + BKE_report(op->reports, RPT_ERROR, "Invalid selection order"); + return OPERATOR_CANCELLED; + } +} + +void MESH_OT_vert_connect_path(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Vertex Connect Path"; + ot->idname = "MESH_OT_vert_connect_path"; + ot->description = "Connect vertices by their selection order, creating edges, splitting faces"; + + /* api callbacks */ + ot->exec = edbm_vert_connect_path_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static int edbm_vert_connect_concave_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (!EDBM_op_call_and_selectf( + em, op, + "faces.out", true, + "connect_verts_concave faces=%hf", + BM_ELEM_SELECT)) + { + return OPERATOR_CANCELLED; + } + + + EDBM_update_generic(em, true, true); + return OPERATOR_FINISHED; +} + +void MESH_OT_vert_connect_concave(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Split Concave Faces"; + ot->idname = "MESH_OT_vert_connect_concave"; + ot->description = "Make all faces convex"; + + /* api callbacks */ + ot->exec = edbm_vert_connect_concave_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + + static int edbm_vert_connect_nonplaner_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -2509,7 +2757,7 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op) if (mode == KNIFE_MIDPOINT) numcuts = 1; BMO_slot_int_set(bmop.slots_in, "cuts", numcuts); - BMO_slot_int_set(bmop.slots_in, "quad_corner_type", SUBD_STRAIGHT_CUT); + BMO_slot_int_set(bmop.slots_in, "quad_corner_type", SUBD_CORNER_STRAIGHT_CUT); BMO_slot_bool_set(bmop.slots_in, "use_single_edge", false); BMO_slot_bool_set(bmop.slots_in, "use_grid_fill", false); @@ -2681,7 +2929,7 @@ static void mesh_separate_material_assign_mat_nr(Object *ob, const short mat_nr) } if (mat_nr < *totcolp) { - ma_obdata = (*matarar)[mat_nr]; + ma_obdata = (*matarar)[mat_nr]; } else { ma_obdata = NULL; @@ -2929,7 +3177,14 @@ static int edbm_fill_exec(bContext *C, wmOperator *op) BMEditMesh *em = BKE_editmesh_from_object(obedit); const bool use_beauty = RNA_boolean_get(op->ptr, "use_beauty"); BMOperator bmop; - + const int totface_orig = em->bm->totface; + int ret; + + if (em->bm->totedgesel == 0) { + BKE_report(op->reports, RPT_WARNING, "No edges selected"); + return OPERATOR_CANCELLED; + } + if (!EDBM_op_init(em, &bmop, op, "triangle_fill edges=%he use_beauty=%b", BM_ELEM_SELECT, use_beauty)) @@ -2939,17 +3194,24 @@ static int edbm_fill_exec(bContext *C, wmOperator *op) BMO_op_exec(em->bm, &bmop); - /* select new geometry */ - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_FACE | BM_EDGE, BM_ELEM_SELECT, true); - - if (!EDBM_op_finish(em, &bmop, op, true)) { - return OPERATOR_CANCELLED; + if (totface_orig != em->bm->totface) { + /* select new geometry */ + BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_FACE | BM_EDGE, BM_ELEM_SELECT, true); + + EDBM_update_generic(em, true, true); + + ret = OPERATOR_FINISHED; + } + else { + BKE_report(op->reports, RPT_WARNING, "No faces filled"); + ret = OPERATOR_CANCELLED; } - EDBM_update_generic(em, true, true); - - return OPERATOR_FINISHED; + if (!EDBM_op_finish(em, &bmop, op, true)) { + ret = OPERATOR_CANCELLED; + } + return ret; } void MESH_OT_fill(wmOperatorType *ot) @@ -3472,10 +3734,16 @@ void MESH_OT_tris_convert_to_quads(wmOperatorType *ot) /* -------------------------------------------------------------------- */ /* Dissolve */ -static void edbm_dissolve_prop__use_verts(wmOperatorType *ot) +static void edbm_dissolve_prop__use_verts(wmOperatorType *ot, bool value, int flag) { - RNA_def_boolean(ot->srna, "use_verts", 0, "Dissolve Verts", - "Dissolve remaining vertices"); + PropertyRNA *prop; + + prop = RNA_def_boolean(ot->srna, "use_verts", value, "Dissolve Verts", + "Dissolve remaining vertices"); + + if (flag) { + RNA_def_property_flag(prop, flag); + } } static void edbm_dissolve_prop__use_face_split(wmOperatorType *ot) { @@ -3560,7 +3828,7 @@ void MESH_OT_dissolve_edges(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - edbm_dissolve_prop__use_verts(ot); + edbm_dissolve_prop__use_verts(ot, true, 0); edbm_dissolve_prop__use_face_split(ot); } @@ -3599,7 +3867,7 @@ void MESH_OT_dissolve_faces(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - edbm_dissolve_prop__use_verts(ot); + edbm_dissolve_prop__use_verts(ot, false, 0); } @@ -3607,6 +3875,15 @@ static int edbm_dissolve_mode_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); + PropertyRNA *prop; + + prop = RNA_struct_find_property(op->ptr, "use_verts"); + if (!RNA_property_is_set(op->ptr, prop)) { + /* always enable in edge-mode */ + if ((em->selectmode & SCE_SELECT_FACE) == 0) { + RNA_property_boolean_set(op->ptr, prop, true); + } + } if (em->selectmode & SCE_SELECT_VERTEX) { return edbm_dissolve_verts_exec(C, op); @@ -3633,7 +3910,7 @@ void MESH_OT_dissolve_mode(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - edbm_dissolve_prop__use_verts(ot); + edbm_dissolve_prop__use_verts(ot, false, PROP_SKIP_SAVE); edbm_dissolve_prop__use_face_split(ot); edbm_dissolve_prop__use_boundary_tear(ot); } @@ -4482,7 +4759,7 @@ static int edbm_noise_exec(bContext *C, wmOperator *op) BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { float tin, dum; - externtex(ma->mtex[0], eve->co, &tin, &dum, &dum, &dum, &dum, 0, NULL); + externtex(ma->mtex[0], eve->co, &tin, &dum, &dum, &dum, &dum, 0, NULL, false); eve->co[2] += fac * tin; } } |