diff options
Diffstat (limited to 'source/blender/editors/mesh/editmesh_rip.c')
-rw-r--r-- | source/blender/editors/mesh/editmesh_rip.c | 361 |
1 files changed, 312 insertions, 49 deletions
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c index 001d584416f..6379bdbc0ca 100644 --- a/source/blender/editors/mesh/editmesh_rip.c +++ b/source/blender/editors/mesh/editmesh_rip.c @@ -55,19 +55,59 @@ #include "mesh_intern.h" -/* helper to find edge for edge_rip */ -static float edbm_rip_rip_edgedist(ARegion *ar, float mat[][4], - const float co1[3], const float co2[3], const float mvalf[2]) +/** + * helper to find edge for edge_rip, + * + * \param inset is used so we get some useful distance + * when comparing multiple edges that meet at the same + * point and would result in teh same distance. + */ +#define INSET_DEFAULT 0.00001f +static float edbm_rip_edgedist(ARegion *ar, float mat[][4], + const float co1[3], const float co2[3], const float mvalf[2], + const float inset) { - float vec1[3], vec2[3]; + float vec1[2], vec2[2]; ED_view3d_project_float_v2_m4(ar, co1, vec1, mat); ED_view3d_project_float_v2_m4(ar, co2, vec2, mat); + if (inset != 0.0f) { + const float dist = inset / len_v2v2(vec1, vec2); + interp_v2_v2v2(vec1, vec1, vec2, dist); + interp_v2_v2v2(vec2, vec2, vec1, dist); + } + /* TODO: use dist_squared_to_line_segment_v2() looks like we only ever use for comparison */ return dist_to_line_segment_v2(mvalf, vec1, vec2); } +#if 0 +static float edbm_rip_linedist(ARegion *ar, float mat[][4], + const float co1[3], const float co2[3], const float mvalf[2]) +{ + float vec1[2], vec2[2]; + + ED_view3d_project_float_v2_m4(ar, co1, vec1, mat); + ED_view3d_project_float_v2_m4(ar, co2, vec2, mat); + + return dist_to_line_v2(mvalf, vec1, vec2); +} +#endif + +/* calculaters a point along the loop tangent which can be used to measure against edges */ +static void edbm_calc_loop_co(BMLoop *l, float l_mid_co[3]) +{ + BM_loop_calc_face_tangent(l, l_mid_co); + + /* scale to average of surrounding edge size, only needs to be approx, but should + * be roughly equivalent to the check below which uses the middle of the edge. */ + mul_v3_fl(l_mid_co, (BM_edge_calc_length(l->e) + BM_edge_calc_length(l->prev->e)) / 2.0f); + + add_v3_v3(l_mid_co, l->v->co); +} + + static float edbm_rip_edge_side_measure(BMEdge *e, BMLoop *e_l, ARegion *ar, float projectMat[4][4], const float fmval[2]) @@ -237,7 +277,6 @@ static EdgeLoopPair *edbm_ripsel_looptag_helper(BMesh *bm) uid_start = uid; while ((e = edbm_ripsel_edge_mark_step(v_step, uid))) { - BM_elem_flag_disable(e, BM_ELEM_SMOOTH); v_step = BM_edge_other_vert((e_step = e), v_step); uid++; /* only different line */ tot++; @@ -254,7 +293,6 @@ static EdgeLoopPair *edbm_ripsel_looptag_helper(BMesh *bm) v_step = e_first->v1; while ((e = edbm_ripsel_edge_mark_step(v_step, uid))) { - BM_elem_flag_disable(e, BM_ELEM_SMOOTH); v_step = BM_edge_other_vert((e_step = e), v_step); uid--; /* only different line */ tot++; @@ -344,6 +382,145 @@ static void edbm_ripsel_deselect_helper(BMesh *bm, EdgeLoopPair *eloop_pairs, } /* --- end 'ripsel' selection handling code --- */ + +/* --- face-fill code --- */ +/** + * return an un-ordered array of loop pairs + * use for rebuilding face-fill + * + * \note the method currenly used fails for edges with 3+ face users and gives + * nasty holes in the mesh, there isnt a good way of knowing ahead of time + * which loops will be split apart (its possible to figure out but quite involved). + * So for now this is a known limitation of current rip-fill option. + */ + +typedef struct UnorderedLoopPair { + BMLoop *l_pair[2]; + char flag; +} UnorderedLoopPair; +enum { + ULP_FLIP_0 = (1 << 0), + ULP_FLIP_1 = (1 << 1) +}; + +static UnorderedLoopPair *edbm_tagged_loop_pairs_to_fill(BMesh *bm) +{ + BMIter iter; + BMEdge *e; + + unsigned int total_tag = 0; + /* count tags, could be pre-calculated */ + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + total_tag++; + } + } + + if (total_tag) { + UnorderedLoopPair *uloop_pairs = MEM_mallocN(total_tag * sizeof(UnorderedLoopPair), __func__); + UnorderedLoopPair *ulp = uloop_pairs; + + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + BMLoop *l1, *l2; + if (BM_edge_loop_pair(e, &l1, &l2)) { + BMVert *v_cmp = l1->e->v1; + ulp->flag = (((l1->v != v_cmp) ? ULP_FLIP_0 : 0) | + ((l2->v == v_cmp) ? ULP_FLIP_1 : 0)); + } + else { + ulp->flag = 0; + } + ulp->l_pair[0] = l1; + ulp->l_pair[1] = l2; + + ulp++; + } + } + + return uloop_pairs; + } + else { + return NULL; + } +} + +static void edbm_tagged_loop_pairs_do_fill_faces(BMesh *bm, UnorderedLoopPair *uloop_pairs) +{ + UnorderedLoopPair *ulp; + unsigned int total_tag = MEM_allocN_len(uloop_pairs) / sizeof(UnorderedLoopPair); + unsigned int i; + + for (i = 0, ulp = uloop_pairs; i < total_tag; i++, ulp++) { + if ((ulp->l_pair[0] && ulp->l_pair[1]) && + (ulp->l_pair[0]->e != ulp->l_pair[1]->e)) + { + /* time has come to make a face! */ + BMVert *v_shared = BM_edge_share_vert(ulp->l_pair[0]->e, ulp->l_pair[1]->e); + BMFace *f, *f_example = ulp->l_pair[0]->f; + BMLoop *l_iter; + BMVert *f_verts[4]; + + if (v_shared == NULL) { + /* quad */ + f_verts[0] = ulp->l_pair[0]->e->v1; + f_verts[1] = ulp->l_pair[1]->e->v1; + f_verts[2] = ulp->l_pair[1]->e->v2; + f_verts[3] = ulp->l_pair[0]->e->v2; + + if (ulp->flag & ULP_FLIP_0) { + SWAP(BMVert *, f_verts[0], f_verts[3]); + } + if (ulp->flag & ULP_FLIP_1) { + SWAP(BMVert *, f_verts[1], f_verts[2]); + } + } + else { + /* tri */ + f_verts[0] = v_shared; + f_verts[1] = BM_edge_other_vert(ulp->l_pair[0]->e, v_shared); + f_verts[2] = BM_edge_other_vert(ulp->l_pair[1]->e, v_shared); + f_verts[3] = NULL; + + /* don't use the flip flags */ + if (v_shared == ulp->l_pair[0]->v) { + SWAP(BMVert *, f_verts[0], f_verts[1]); + } + } + + /* face should never exist */ + BLI_assert(BM_face_exists(bm, f_verts, f_verts[3] ? 4 : 3, &f) == FALSE); + + f = BM_face_create_quad_tri_v(bm, f_verts, f_verts[3] ? 4 : 3, f_example, FALSE); + + l_iter = BM_FACE_FIRST_LOOP(f); + + if (f_verts[3]) { + BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next; + BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter); l_iter = l_iter->next; + BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter); l_iter = l_iter->next; + BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); + } + else { + if (v_shared == f_verts[0]) { + BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next; + BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next; + BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter); + } + else { + BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next; + BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next; + BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter); + } + } + + } + } +} + +/* --- end 'face-fill' code --- */ + + static int edbm_rip_call_edgesplit(BMEditMesh *em, wmOperator *op) { BMOperator bmop; @@ -366,6 +543,8 @@ static int edbm_rip_call_edgesplit(BMEditMesh *em, wmOperator *op) */ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, wmEvent *event) { + const int do_fill = RNA_boolean_get(op->ptr, "use_fill"); + UnorderedLoopPair *fill_uloop_pairs = NULL; Object *obedit = CTX_data_edit_object(C); ARegion *ar = CTX_wm_region(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); @@ -388,7 +567,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, wmEvent *event) ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat); /* find selected vert - same some time and check history first */ - if (BM_select_history_active_get(em->bm, &ese) && ese.htype == BM_VERT) { + if (BM_select_history_active_get(bm, &ese) && ese.htype == BM_VERT) { v = (BMVert *)ese.ele; } else { @@ -417,7 +596,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, wmEvent *event) totboundary_edge += (is_boundary != 0 || BM_edge_is_wire(e)); if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { if (is_boundary == FALSE && BM_edge_is_manifold(e)) { - d = edbm_rip_rip_edgedist(ar, projectMat, e->v1->co, e->v2->co, fmval); + d = edbm_rip_edgedist(ar, projectMat, e->v1->co, e->v2->co, fmval, INSET_DEFAULT); if (d < dist) { dist = d; e2 = e; @@ -426,6 +605,42 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, wmEvent *event) } } + /* if we are ripping a single vertex from 3 faces, + * then measure the distance to the face corner as well as the edge */ + if (BM_vert_face_count(v) == 3 && + BM_vert_edge_count(v) == 3) + { + BMEdge *e_all[3]; + BMLoop *l_all[3]; + int i1, i2; + + BM_iter_as_array(bm, BM_EDGES_OF_VERT, v, (void **)e_all, 3); + BM_iter_as_array(bm, BM_LOOPS_OF_VERT, v, (void **)l_all, 3); + + /* not do a loop similar to the one above, but test against loops */ + for (i1 = 0; i1 < 3; i1++) { + /* consider wire as boundary for this purpose, + * otherwise we can't a face away from a wire edge */ + float l_mid_co[3]; + l = l_all[i1]; + edbm_calc_loop_co(l, l_mid_co); + d = edbm_rip_edgedist(ar, projectMat, l->v->co, l_mid_co, fmval, INSET_DEFAULT); + + if (d < dist) { + dist = d; + + /* find the edge that is not in this loop */ + e2 = NULL; + for (i2 = 0; i2 < 3; i2++) { + if (!BM_edge_in_loop(e_all[i2], l)) { + e2 = e_all[i2]; + break; + } + } + BLI_assert(e2 != NULL); + } + } + } } /* should we go ahead with edge rip or do we need to do special case, split off vertex?: @@ -459,7 +674,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, wmEvent *event) int vi_best = 0; if (ese.ele) { - BM_select_history_remove(em->bm, ese.ele); + BM_select_history_remove(bm, ese.ele); } dist = FLT_MAX; @@ -473,14 +688,9 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, wmEvent *event) BM_ITER_ELEM (l, &iter, vout[i], BM_LOOPS_OF_VERT) { if (!BM_elem_flag_test(l->f, BM_ELEM_HIDDEN)) { float l_mid_co[3]; - BM_loop_calc_face_tangent(l, l_mid_co); + edbm_calc_loop_co(l, l_mid_co); - /* scale to average of surrounding edge size, only needs to be approx, but should - * be roughly equivalent to the check below which uses the middle of the edge. */ - mul_v3_fl(l_mid_co, (BM_edge_calc_length(l->e) + BM_edge_calc_length(l->prev->e)) / 2.0f); - add_v3_v3(l_mid_co, v->co); - - d = edbm_rip_rip_edgedist(ar, projectMat, v->co, l_mid_co, fmval); + d = edbm_rip_edgedist(ar, projectMat, v->co, l_mid_co, fmval, INSET_DEFAULT); if (d < dist) { dist = d; @@ -496,7 +706,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, wmEvent *event) float e_mid_co[3]; mid_v3_v3v3(e_mid_co, e->v1->co, e->v2->co); - d = edbm_rip_rip_edgedist(ar, projectMat, v->co, e_mid_co, fmval); + d = edbm_rip_edgedist(ar, projectMat, v->co, e_mid_co, fmval, INSET_DEFAULT); if (d < dist) { dist = d; @@ -512,7 +722,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, wmEvent *event) BM_vert_select_set(bm, v, TRUE); if (ese.ele) { - BM_select_history_store(em->bm, v); + BM_select_history_store(bm, v); } /* splice all others back together */ @@ -543,39 +753,65 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_CANCELLED; } + /* *** Execute the split! *** */ + /* unlike edge split, for single vertex split we only use the operator in one of the cases + * but both allocate fill */ + /* rip two adjacent edges */ if (BM_edge_is_boundary(e2) || BM_vert_face_count(v) == 2) { + /* Don't run the edge split operator in this case */ + + BM_elem_flag_enable(e2, BM_ELEM_TAG); /* only for face-fill (we don't call the operator) */ + + /* keep directly before edgesplit */ + if (do_fill) { + fill_uloop_pairs = edbm_tagged_loop_pairs_to_fill(bm); + } + l = e2->l; ripvert = BM_face_vert_separate(bm, l->f, v); BLI_assert(ripvert); if (!ripvert) { + if (fill_uloop_pairs) MEM_freeN(fill_uloop_pairs); return OPERATOR_CANCELLED; } } - else if (BM_edge_is_manifold(e2)) { - l = e2->l; - e = BM_face_other_edge_loop(l->f, e2, v)->e; - BM_elem_flag_enable(e, BM_ELEM_TAG); + else { + if (BM_edge_is_manifold(e2)) { + l = e2->l; + e = BM_face_other_edge_loop(l->f, e2, v)->e; + BM_elem_flag_enable(e, BM_ELEM_TAG); + + l = e2->l->radial_next; + e = BM_face_other_edge_loop(l->f, e2, v)->e; + BM_elem_flag_enable(e, BM_ELEM_TAG); + } + else { + /* looks like there are no split edges, we could just return/report-error? - Campbell */ + } + + /* keep directly before edgesplit */ + if (do_fill) { + fill_uloop_pairs = edbm_tagged_loop_pairs_to_fill(bm); + } - l = e2->l->radial_next; - e = BM_face_other_edge_loop(l->f, e2, v)->e; - BM_elem_flag_enable(e, BM_ELEM_TAG); + if (!edbm_rip_call_edgesplit(em, op)) { + if (fill_uloop_pairs) MEM_freeN(fill_uloop_pairs); + return OPERATOR_CANCELLED; + } } dist = FLT_MAX; - if (!edbm_rip_call_edgesplit(em, op)) { - return OPERATOR_CANCELLED; - } - else { + { /* --- select which vert --- */ BMVert *v_best = NULL; float l_prev_co[3], l_next_co[3], l_corner_co[3]; float scale; dist = FLT_MAX; - BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { /* disable by default, re-enable winner at end */ BM_vert_select_set(bm, v, FALSE); @@ -593,7 +829,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, wmEvent *event) add_v3_v3v3(l_corner_co, l_prev_co, l_next_co); add_v3_v3(l_corner_co, l->v->co); - d = edbm_rip_rip_edgedist(ar, projectMat, l->v->co, l_corner_co, fmval); + d = edbm_rip_edgedist(ar, projectMat, l->v->co, l_corner_co, fmval, INSET_DEFAULT); if (d < dist) { v_best = v; dist = d; @@ -605,11 +841,17 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, wmEvent *event) if (v_best) { BM_vert_select_set(bm, v_best, TRUE); if (ese.ele) { - BM_select_history_store(em->bm, v_best); + BM_select_history_store(bm, v_best); } } } + if (do_fill && fill_uloop_pairs) { + edbm_tagged_loop_pairs_do_fill_faces(bm, fill_uloop_pairs); + MEM_freeN(fill_uloop_pairs); + } + + if (totvert_orig == bm->totvert) { BKE_report(op->reports, RPT_ERROR, "No vertices could be ripped"); return OPERATOR_CANCELLED; @@ -623,6 +865,8 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, wmEvent *event) */ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, wmEvent *event) { + const int do_fill = RNA_boolean_get(op->ptr, "use_fill"); + UnorderedLoopPair *fill_uloop_pairs = NULL; Object *obedit = CTX_data_edit_object(C); ARegion *ar = CTX_wm_region(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); @@ -633,25 +877,25 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, wmEvent *event) BMEdge *e, *e2; BMVert *v; const int totedge_orig = bm->totedge; - int i; float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]}; - int totedge; - int all_minifold; - EdgeLoopPair *eloop_pairs; ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat); - /* important this runs on the original selection, before tempering with tagging */ + /* important this runs on the original selection, before tampering with tagging */ eloop_pairs = edbm_ripsel_looptag_helper(bm); /* expand edge selection */ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + int all_manifold; + int totedge_manifold; /* manifold, visible edges */ + int i; + e2 = NULL; i = 0; - totedge = 0; - all_minifold = TRUE; + totedge_manifold = 0; + all_manifold = TRUE; BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { if (!BM_edge_is_wire(e) && @@ -663,22 +907,25 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, wmEvent *event) e2 = e; i++; } - totedge++; + totedge_manifold++; } /** #BM_vert_other_disk_edge has no hidden checks so don't check hidden here */ - if ((all_minifold == TRUE) && (BM_edge_is_manifold(e) == FALSE)) { - all_minifold = FALSE; + if ((all_manifold == TRUE) && (BM_edge_is_manifold(e) == FALSE)) { + all_manifold = FALSE; } } /* single edge, extend */ if (i == 1 && e2->l) { - if ((totedge == 4) || (all_minifold == FALSE)) { + /* note: if the case of 3 edges has one change in loop stepping, + * if this becomes more involved we may be better off splitting + * the 3 edge case into its own else-if branch */ + if ((totedge_manifold == 4 || totedge_manifold == 3) || (all_manifold == FALSE)) { BMLoop *l_a = e2->l; BMLoop *l_b = l_a->radial_next; - /* find the best face to follow, this what the edge won't point away from + /* find the best face to follow, this way the edge won't point away from * the mouse when there are more then 4 (takes the shortest face fan around) */ l = (edbm_rip_edge_side_measure(e2, l_a, ar, projectMat, fmval) < edbm_rip_edge_side_measure(e2, l_b, ar, projectMat, fmval)) ? l_a : l_b; @@ -688,9 +935,12 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, wmEvent *event) * not crashing but adds duplicate edge. */ if (BM_edge_is_manifold(l->e)) { l = l->radial_next; - l = BM_face_other_edge_loop(l->f, l->e, v); + + if (totedge_manifold != 3) + l = BM_face_other_edge_loop(l->f, l->e, v); if (l) { + BLI_assert(!BM_elem_flag_test(l->e, BM_ELEM_TAG)); BM_elem_flag_enable(l->e, BM_ELEM_TAG); } } @@ -699,13 +949,20 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, wmEvent *event) e = BM_vert_other_disk_edge(v, e2); if (e) { + BLI_assert(!BM_elem_flag_test(e, BM_ELEM_TAG)); BM_elem_flag_enable(e, BM_ELEM_TAG); } } } } + /* keep directly before edgesplit */ + if (do_fill) { + fill_uloop_pairs = edbm_tagged_loop_pairs_to_fill(bm); + } + if (!edbm_rip_call_edgesplit(em, op)) { + if (fill_uloop_pairs) MEM_freeN(fill_uloop_pairs); return OPERATOR_CANCELLED; } @@ -718,6 +975,11 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, wmEvent *event) ar, projectMat, fmval); MEM_freeN(eloop_pairs); + if (do_fill && fill_uloop_pairs) { + edbm_tagged_loop_pairs_do_fill_faces(bm, fill_uloop_pairs); + MEM_freeN(fill_uloop_pairs); + } + if (totedge_orig == bm->totedge) { BKE_report(op->reports, RPT_ERROR, "No edges could be ripped"); return OPERATOR_CANCELLED; @@ -740,12 +1002,12 @@ static int edbm_rip_invoke(bContext *C, wmOperator *op, wmEvent *event) int ret; /* running in face mode hardly makes sense, so convert to region loop and rip */ - if (em->bm->totfacesel) { + if (bm->totfacesel) { /* highly nifty but hard to support since the operator can fail and we're left * with modified selection */ // WM_operator_name_call(C, "MESH_OT_region_to_loop", WM_OP_INVOKE_DEFAULT, NULL); - BKE_report(op->reports, RPT_ERROR, "Can't rip selected faces"); + BKE_report(op->reports, RPT_ERROR, "Cannot rip selected faces"); return OPERATOR_CANCELLED; } @@ -760,7 +1022,7 @@ static int edbm_rip_invoke(bContext *C, wmOperator *op, wmEvent *event) */ /* BM_ELEM_SELECT --> BM_ELEM_TAG */ - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT)); } @@ -804,5 +1066,6 @@ void MESH_OT_rip(wmOperatorType *ot) /* to give to transform */ Transform_Properties(ot, P_PROPORTIONAL); - RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", ""); + RNA_def_boolean(ot->srna, "mirror", FALSE, "Mirror Editing", ""); + RNA_def_boolean(ot->srna, "use_fill", FALSE, "Fill", "Fill the ripped region"); } |