diff options
Diffstat (limited to 'source/blender/editors/mesh')
-rw-r--r-- | source/blender/editors/mesh/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_bevel.c | 116 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_extrude.c | 182 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_inset.c | 75 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_intersect.c | 400 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_knife.c | 213 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_knife_project.c | 2 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_loopcut.c | 96 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_rip.c | 6 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_select.c | 46 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_tools.c | 51 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_utils.c | 9 | ||||
-rw-r--r-- | source/blender/editors/mesh/mesh_data.c | 11 | ||||
-rw-r--r-- | source/blender/editors/mesh/mesh_intern.h | 4 | ||||
-rw-r--r-- | source/blender/editors/mesh/mesh_navmesh.c | 2 | ||||
-rw-r--r-- | source/blender/editors/mesh/mesh_ops.c | 2 |
16 files changed, 868 insertions, 348 deletions
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt index a5e98b651a3..db20d42f39d 100644 --- a/source/blender/editors/mesh/CMakeLists.txt +++ b/source/blender/editors/mesh/CMakeLists.txt @@ -46,6 +46,7 @@ set(SRC editmesh_bisect.c editmesh_extrude.c editmesh_inset.c + editmesh_intersect.c editmesh_knife.c editmesh_knife_project.c editmesh_loopcut.c diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index e25919b7400..48d5113a279 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -73,9 +73,9 @@ typedef struct { #define HEADER_LENGTH 180 -static void edbm_bevel_update_header(wmOperator *op, bContext *C) +static void edbm_bevel_update_header(bContext *C, wmOperator *op) { - const char *str = IFACE_("Confirm: (Enter/LMB), Cancel: (Esc/RMB), Offset: %s, Segments: %d"); + const char *str = IFACE_("Confirm: (Enter/LMB), Cancel: (Esc/RMB), Mode: %s (M), Offset: %s, Segments: %d"); char msg[HEADER_LENGTH]; ScrArea *sa = CTX_wm_area(C); @@ -84,15 +84,19 @@ static void edbm_bevel_update_header(wmOperator *op, bContext *C) if (sa) { BevelData *opdata = op->customdata; char offset_str[NUM_STR_REP_LEN]; + const char *type_str; + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "offset_type"); if (hasNumInput(&opdata->num_input)) { - outputNumInput(&opdata->num_input, offset_str, sce->unit.scale_length); + outputNumInput(&opdata->num_input, offset_str, &sce->unit); } else { BLI_snprintf(offset_str, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "offset")); } - BLI_snprintf(msg, HEADER_LENGTH, str, offset_str, RNA_int_get(op->ptr, "segments")); + RNA_property_enum_name_gettexted(C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &type_str); + + BLI_snprintf(msg, HEADER_LENGTH, str, type_str, offset_str, RNA_int_get(op->ptr, "segments")); ED_area_headerprint(sa, msg); } @@ -146,15 +150,19 @@ static bool edbm_bevel_calc(wmOperator *op) const int segments = RNA_int_get(op->ptr, "segments"); const float profile = RNA_float_get(op->ptr, "profile"); const bool vertex_only = RNA_boolean_get(op->ptr, "vertex_only"); + int material = RNA_int_get(op->ptr, "material"); /* revert to original mesh */ if (opdata->is_modal) { EDBM_redo_state_restore(opdata->mesh_backup, em, false); } + if (em->ob) + material = CLAMPIS(material, -1, em->ob->totcol - 1); + EDBM_op_init(em, &bmop, op, - "bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f", - BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile); + "bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f material=%i", + BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile, material); BMO_op_exec(em->bm, &bmop); @@ -254,7 +262,7 @@ static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event) opdata->initial_length = len_v2(mlen); opdata->pixel_size = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f; - edbm_bevel_update_header(op, C); + edbm_bevel_update_header(C, op); if (!edbm_bevel_calc(op)) { edbm_bevel_cancel(C, op); @@ -269,44 +277,40 @@ static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event) static float edbm_bevel_mval_factor(wmOperator *op, const wmEvent *event) { BevelData *opdata = op->customdata; - bool use_dist = true; - bool is_percent = false; + bool use_dist; + bool is_percent; float mdiff[2]; float factor; mdiff[0] = opdata->mcenter[0] - event->mval[0]; mdiff[1] = opdata->mcenter[1] - event->mval[1]; is_percent = (RNA_enum_get(op->ptr, "offset_type") == BEVEL_AMT_PERCENT); + use_dist = !is_percent; - if (use_dist) { - factor = ((len_v2(mdiff) - MVAL_PIXEL_MARGIN) - opdata->initial_length) * opdata->pixel_size; - } - else { - factor = (len_v2(mdiff) - MVAL_PIXEL_MARGIN) / opdata->initial_length; - factor = factor - 1.0f; /* a different kind of buffer where nothing happens */ - } + factor = ((len_v2(mdiff) - MVAL_PIXEL_MARGIN) - opdata->initial_length) * opdata->pixel_size; /* Fake shift-transform... */ if (event->shift) { if (opdata->shift_factor < 0.0f) { opdata->shift_factor = RNA_float_get(op->ptr, "offset"); + if (is_percent) { + opdata->shift_factor /= 100.0f; + } } factor = (factor - opdata->shift_factor) * 0.1f + opdata->shift_factor; } - else if (opdata->shift_factor >= 0.0f) + else if (opdata->shift_factor >= 0.0f) { opdata->shift_factor = -1.0f; + } /* clamp differently based on distance/factor */ if (use_dist) { if (factor < 0.0f) factor = 0.0f; } else { + CLAMP(factor, 0.0f, 1.0f); if (is_percent) { factor *= 100.0f; - CLAMP(factor, 0.0f, 100.0f); - } - else { - CLAMP(factor, 0.0f, 1.0f); } } @@ -317,17 +321,16 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) { BevelData *opdata = op->customdata; int segments = RNA_int_get(op->ptr, "segments"); - - if (event->val == KM_PRESS && hasNumInput(&opdata->num_input)) { - /* Modal numinput active, try to handle numeric inputs first... */ - if (handleNumInput(C, &opdata->num_input, event)) { - float value = RNA_float_get(op->ptr, "offset"); - applyNumInput(&opdata->num_input, &value); - RNA_float_set(op->ptr, "offset", value); - edbm_bevel_calc(op); - edbm_bevel_update_header(op, C); - return OPERATOR_RUNNING_MODAL; - } + const bool has_numinput = hasNumInput(&opdata->num_input); + + /* Modal numinput active, try to handle numeric inputs first... */ + if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &opdata->num_input, event)) { + float value = RNA_float_get(op->ptr, "offset"); + applyNumInput(&opdata->num_input, &value); + RNA_float_set(op->ptr, "offset", value); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + return OPERATOR_RUNNING_MODAL; } else { bool handled = false; @@ -338,12 +341,12 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_CANCELLED; case MOUSEMOVE: - if (!hasNumInput(&opdata->num_input)) { + if (!has_numinput) { const float factor = edbm_bevel_mval_factor(op, event); RNA_float_set(op->ptr, "offset", factor); edbm_bevel_calc(op); - edbm_bevel_update_header(op, C); + edbm_bevel_update_header(C, op); handled = true; } break; @@ -368,7 +371,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) segments++; RNA_int_set(op->ptr, "segments", segments); edbm_bevel_calc(op); - edbm_bevel_update_header(op, C); + edbm_bevel_update_header(C, op); handled = true; break; @@ -380,21 +383,41 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) segments = max_ii(segments - 1, 1); RNA_int_set(op->ptr, "segments", segments); edbm_bevel_calc(op); - edbm_bevel_update_header(op, C); + edbm_bevel_update_header(C, op); handled = true; break; - } - if (!handled && event->val == KM_PRESS) { - /* Modal numinput inactive, try to handle numeric inputs last... */ - if (handleNumInput(C, &opdata->num_input, event)) { - float value = RNA_float_get(op->ptr, "offset"); - applyNumInput(&opdata->num_input, &value); - RNA_float_set(op->ptr, "offset", value); + case MKEY: + if (event->val == KM_RELEASE) + break; + + { + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "offset_type"); + int type = RNA_property_enum_get(op->ptr, prop); + type++; + if (type > BEVEL_AMT_PERCENT) { + type = BEVEL_AMT_OFFSET; + } + RNA_property_enum_set(op->ptr, prop, type); + } + /* Update factor accordingly to new offset_type. */ + if (!has_numinput) { + RNA_float_set(op->ptr, "offset", edbm_bevel_mval_factor(op, event)); + } edbm_bevel_calc(op); - edbm_bevel_update_header(op, C); - return OPERATOR_RUNNING_MODAL; - } + edbm_bevel_update_header(C, op); + handled = true; + break; + } + + /* Modal numinput inactive, try to handle numeric inputs last... */ + if (!handled && event->val == KM_PRESS && handleNumInput(C, &opdata->num_input, event)) { + float value = RNA_float_get(op->ptr, "offset"); + applyNumInput(&opdata->num_input, &value); + RNA_float_set(op->ptr, "offset", value); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + return OPERATOR_RUNNING_MODAL; } } @@ -445,4 +468,5 @@ void MESH_OT_bevel(wmOperatorType *ot) RNA_def_int(ot->srna, "segments", 1, 1, 50, "Segments", "Segments for curved edge", 1, 8); RNA_def_float(ot->srna, "profile", 0.5f, 0.15f, 1.0f, "Profile", "Controls profile shape (0.5 = round)", 0.15f, 1.0f); RNA_def_boolean(ot->srna, "vertex_only", false, "Vertex only", "Bevel only vertices"); + RNA_def_int(ot->srna, "material", -1, -1, INT_MAX, "Material", "Material for bevel faces (-1 means use adjacent faces)", -1, 100); } diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index 595c43c1060..3e403387a67 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -33,6 +33,7 @@ #include "DNA_object_types.h" #include "BLI_math.h" +#include "BLI_listbase.h" #include "BKE_context.h" #include "BKE_global.h" @@ -65,6 +66,75 @@ static void add_normal_aligned(float nor[3], const float add[3]) } } +static void edbm_extrude_edge_exclude_mirror( + Object *obedit, BMEditMesh *em, + const char hflag, + BMOperator *op, BMOpSlot *slot_edges_exclude) +{ + BMesh *bm = em->bm; + ModifierData *md; + + /* If a mirror modifier with clipping is on, we need to adjust some + * of the cases above to handle edges on the line of symmetry. + */ + for (md = obedit->modifiers.first; md; md = md->next) { + if ((md->type == eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) { + MirrorModifierData *mmd = (MirrorModifierData *) md; + + if (mmd->flag & MOD_MIR_CLIPPING) { + BMIter iter; + BMEdge *edge; + + float mtx[4][4]; + if (mmd->mirror_ob) { + float imtx[4][4]; + invert_m4_m4(imtx, mmd->mirror_ob->obmat); + mul_m4_m4m4(mtx, imtx, obedit->obmat); + } + + BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(edge, hflag) && + BM_edge_is_boundary(edge) && + BM_elem_flag_test(edge->l->f, hflag)) + { + float co1[3], co2[3]; + + copy_v3_v3(co1, edge->v1->co); + copy_v3_v3(co2, edge->v2->co); + + if (mmd->mirror_ob) { + mul_v3_m4v3(co1, mtx, co1); + mul_v3_m4v3(co2, mtx, co2); + } + + if (mmd->flag & MOD_MIR_AXIS_X) { + if ((fabsf(co1[0]) < mmd->tolerance) && + (fabsf(co2[0]) < mmd->tolerance)) + { + BMO_slot_map_empty_insert(op, slot_edges_exclude, edge); + } + } + if (mmd->flag & MOD_MIR_AXIS_Y) { + if ((fabsf(co1[1]) < mmd->tolerance) && + (fabsf(co2[1]) < mmd->tolerance)) + { + BMO_slot_map_empty_insert(op, slot_edges_exclude, edge); + } + } + if (mmd->flag & MOD_MIR_AXIS_Z) { + if ((fabsf(co1[2]) < mmd->tolerance) && + (fabsf(co2[2]) < mmd->tolerance)) + { + BMO_slot_map_empty_insert(op, slot_edges_exclude, edge); + } + } + } + } + } + } + } +} + /* individual face extrude */ /* will use vertex normals for extrusion directions, so *nor is unaffected */ static short edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const char hflag, float *UNUSED(nor)) @@ -75,7 +145,10 @@ static short edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const c BMLoop *l; BMOperator bmop; - EDBM_op_init(em, &bmop, op, "extrude_discrete_faces faces=%hf", hflag); + EDBM_op_init( + em, &bmop, op, + "extrude_discrete_faces faces=%hf use_select_history=%b", + hflag, true); /* deselect original verts */ EDBM_flag_disable_all(em, BM_ELEM_SELECT); @@ -101,12 +174,18 @@ static short edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const c /* extrudes individual edges */ static short edbm_extrude_edges_indiv(BMEditMesh *em, wmOperator *op, const char hflag, float *UNUSED(nor)) { + BMesh *bm = em->bm; BMOperator bmop; - EDBM_op_init(em, &bmop, op, "extrude_edge_only edges=%he", hflag); + EDBM_op_init( + em, &bmop, op, + "extrude_edge_only edges=%he use_select_history=%b", + hflag, true); /* deselect original verts */ + BM_SELECT_HISTORY_BACKUP(bm); EDBM_flag_disable_all(em, BM_ELEM_SELECT); + BM_SELECT_HISTORY_RESTORE(bm); BMO_op_exec(em->bm, &bmop); BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_VERT | BM_EDGE, BM_ELEM_SELECT, true); @@ -123,7 +202,10 @@ static short edbm_extrude_verts_indiv(BMEditMesh *em, wmOperator *op, const char { BMOperator bmop; - EDBM_op_init(em, &bmop, op, "extrude_vert_indiv verts=%hv", hflag); + EDBM_op_init( + em, &bmop, op, + "extrude_vert_indiv verts=%hv use_select_history=%b", + hflag, true); /* deselect original verts */ BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_in, "verts", BM_VERT, BM_ELEM_SELECT, true); @@ -138,82 +220,32 @@ static short edbm_extrude_verts_indiv(BMEditMesh *em, wmOperator *op, const char return 'g'; /* g is grab */ } -static short edbm_extrude_edge(Object *obedit, BMEditMesh *em, const char hflag, float nor[3]) +static short edbm_extrude_edge_ex( + Object *obedit, BMEditMesh *em, + const char hflag, float nor[3], + const bool use_mirror, + const bool use_select_history) { BMesh *bm = em->bm; - BMIter iter; BMOIter siter; BMOperator extop; - BMEdge *edge; BMFace *f; - ModifierData *md; BMElem *ele; - BMOpSlot *slot_edges_exclude; BMO_op_init(bm, &extop, BMO_FLAG_DEFAULTS, "extrude_face_region"); + BMO_slot_bool_set(extop.slots_in, "use_select_history", use_select_history); BMO_slot_buffer_from_enabled_hflag(bm, &extop, extop.slots_in, "geom", BM_VERT | BM_EDGE | BM_FACE, hflag); - slot_edges_exclude = BMO_slot_get(extop.slots_in, "edges_exclude"); + if (use_mirror) { + BMOpSlot *slot_edges_exclude; + slot_edges_exclude = BMO_slot_get(extop.slots_in, "edges_exclude"); - /* If a mirror modifier with clipping is on, we need to adjust some - * of the cases above to handle edges on the line of symmetry. - */ - md = obedit->modifiers.first; - for (; md; md = md->next) { - if ((md->type == eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) { - MirrorModifierData *mmd = (MirrorModifierData *) md; - - if (mmd->flag & MOD_MIR_CLIPPING) { - float mtx[4][4]; - if (mmd->mirror_ob) { - float imtx[4][4]; - invert_m4_m4(imtx, mmd->mirror_ob->obmat); - mul_m4_m4m4(mtx, imtx, obedit->obmat); - } - - BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(edge, hflag) && - BM_edge_is_boundary(edge) && - BM_elem_flag_test(edge->l->f, hflag)) - { - float co1[3], co2[3]; - - copy_v3_v3(co1, edge->v1->co); - copy_v3_v3(co2, edge->v2->co); - - if (mmd->mirror_ob) { - mul_v3_m4v3(co1, mtx, co1); - mul_v3_m4v3(co2, mtx, co2); - } - - if (mmd->flag & MOD_MIR_AXIS_X) { - if ((fabsf(co1[0]) < mmd->tolerance) && - (fabsf(co2[0]) < mmd->tolerance)) - { - BMO_slot_map_empty_insert(&extop, slot_edges_exclude, edge); - } - } - if (mmd->flag & MOD_MIR_AXIS_Y) { - if ((fabsf(co1[1]) < mmd->tolerance) && - (fabsf(co2[1]) < mmd->tolerance)) - { - BMO_slot_map_empty_insert(&extop, slot_edges_exclude, edge); - } - } - if (mmd->flag & MOD_MIR_AXIS_Z) { - if ((fabsf(co1[2]) < mmd->tolerance) && - (fabsf(co2[2]) < mmd->tolerance)) - { - BMO_slot_map_empty_insert(&extop, slot_edges_exclude, edge); - } - } - } - } - } - } + edbm_extrude_edge_exclude_mirror(obedit, em, hflag, &extop, slot_edges_exclude); } + BM_SELECT_HISTORY_BACKUP(bm); EDBM_flag_disable_all(em, BM_ELEM_SELECT); + BM_SELECT_HISTORY_RESTORE(bm); BMO_op_exec(bm, &extop); @@ -236,6 +268,13 @@ static short edbm_extrude_edge(Object *obedit, BMEditMesh *em, const char hflag, return is_zero_v3(nor) ? 'g' : 'n'; } +static short edbm_extrude_edge( + Object *obedit, BMEditMesh *em, + const char hflag, float nor[3]) +{ + return edbm_extrude_edge_ex(obedit, em, hflag, nor, true, true); +} + static short edbm_extrude_vert(Object *obedit, BMEditMesh *em, const char hflag, float nor[3]) { BMIter iter; @@ -288,13 +327,12 @@ static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op) mul_m3_v3(tmat, dvec); for (a = 0; a < steps; a++) { - edbm_extrude_edge(obedit, em, BM_ELEM_SELECT, nor); - //BMO_op_callf(em->bm, BMO_FLAG_DEFAULTS, "extrude_face_region geom=%hef", BM_ELEM_SELECT); - BMO_op_callf(em->bm, BMO_FLAG_DEFAULTS, - "translate vec=%v verts=%hv", - dvec, BM_ELEM_SELECT); - //extrudeflag(obedit, em, SELECT, nor); - //translateflag(em, SELECT, dvec); + edbm_extrude_edge_ex(obedit, em, BM_ELEM_SELECT, nor, false, false); + + BMO_op_callf( + em->bm, BMO_FLAG_DEFAULTS, + "translate vec=%v verts=%hv", + dvec, BM_ELEM_SELECT); } EDBM_mesh_normals_update(em); diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c index dc40330b309..a4942d01671 100644 --- a/source/blender/editors/mesh/editmesh_inset.c +++ b/source/blender/editors/mesh/editmesh_inset.c @@ -90,7 +90,7 @@ static void edbm_inset_update_header(wmOperator *op, bContext *C) if (sa) { char flts_str[NUM_STR_REP_LEN * 2]; if (hasNumInput(&opdata->num_input)) - outputNumInput(&opdata->num_input, flts_str, sce->unit.scale_length); + outputNumInput(&opdata->num_input, flts_str, &sce->unit); else { BLI_snprintf(flts_str, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "thickness")); BLI_snprintf(flts_str + NUM_STR_REP_LEN, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "depth")); @@ -297,25 +297,24 @@ static int edbm_inset_invoke(bContext *C, wmOperator *op, const wmEvent *event) static int edbm_inset_modal(bContext *C, wmOperator *op, const wmEvent *event) { InsetData *opdata = op->customdata; - - if (event->val == KM_PRESS && hasNumInput(&opdata->num_input)) { - /* Modal numinput active, try to handle numeric inputs first... */ - if (handleNumInput(C, &opdata->num_input, event)) { - float amounts[2] = {RNA_float_get(op->ptr, "thickness"), - RNA_float_get(op->ptr, "depth")}; - applyNumInput(&opdata->num_input, amounts); - amounts[0] = max_ff(amounts[0], 0.0f); - RNA_float_set(op->ptr, "thickness", amounts[0]); - RNA_float_set(op->ptr, "depth", amounts[1]); - - if (edbm_inset_calc(op)) { - edbm_inset_update_header(op, C); - return OPERATOR_RUNNING_MODAL; - } - else { - edbm_inset_cancel(C, op); - return OPERATOR_CANCELLED; - } + const bool has_numinput = hasNumInput(&opdata->num_input); + + /* Modal numinput active, try to handle numeric inputs first... */ + if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &opdata->num_input, event)) { + float amounts[2] = {RNA_float_get(op->ptr, "thickness"), + RNA_float_get(op->ptr, "depth")}; + applyNumInput(&opdata->num_input, amounts); + amounts[0] = max_ff(amounts[0], 0.0f); + RNA_float_set(op->ptr, "thickness", amounts[0]); + RNA_float_set(op->ptr, "depth", amounts[1]); + + if (edbm_inset_calc(op)) { + edbm_inset_update_header(op, C); + return OPERATOR_RUNNING_MODAL; + } + else { + edbm_inset_cancel(C, op); + return OPERATOR_CANCELLED; } } else { @@ -327,7 +326,7 @@ static int edbm_inset_modal(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_CANCELLED; case MOUSEMOVE: - if (!hasNumInput(&opdata->num_input)) { + if (!has_numinput) { float mdiff[2]; float amount; @@ -455,24 +454,22 @@ static int edbm_inset_modal(bContext *C, wmOperator *op, const wmEvent *event) break; } - if (!handled && event->val == KM_PRESS) { - /* Modal numinput inactive, try to handle numeric inputs last... */ - if (handleNumInput(C, &opdata->num_input, event)) { - float amounts[2] = {RNA_float_get(op->ptr, "thickness"), - RNA_float_get(op->ptr, "depth")}; - applyNumInput(&opdata->num_input, amounts); - amounts[0] = max_ff(amounts[0], 0.0f); - RNA_float_set(op->ptr, "thickness", amounts[0]); - RNA_float_set(op->ptr, "depth", amounts[1]); - - if (edbm_inset_calc(op)) { - edbm_inset_update_header(op, C); - return OPERATOR_RUNNING_MODAL; - } - else { - edbm_inset_cancel(C, op); - return OPERATOR_CANCELLED; - } + /* Modal numinput inactive, try to handle numeric inputs last... */ + if (!handled && event->val == KM_PRESS && handleNumInput(C, &opdata->num_input, event)) { + float amounts[2] = {RNA_float_get(op->ptr, "thickness"), + RNA_float_get(op->ptr, "depth")}; + applyNumInput(&opdata->num_input, amounts); + amounts[0] = max_ff(amounts[0], 0.0f); + RNA_float_set(op->ptr, "thickness", amounts[0]); + RNA_float_set(op->ptr, "depth", amounts[1]); + + if (edbm_inset_calc(op)) { + edbm_inset_update_header(op, C); + return OPERATOR_RUNNING_MODAL; + } + else { + edbm_inset_cancel(C, op); + return OPERATOR_CANCELLED; } } } diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c new file mode 100644 index 00000000000..df6776950d7 --- /dev/null +++ b/source/blender/editors/mesh/editmesh_intersect.c @@ -0,0 +1,400 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/mesh/editmesh_intersect.c + * \ingroup edmesh + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_object_types.h" + +#include "BLI_math.h" +#include "BLI_array.h" +#include "BLI_linklist_stack.h" + + +#include "BKE_context.h" +#include "BKE_report.h" +#include "BKE_editmesh.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_mesh.h" +#include "ED_screen.h" + +#include "intern/bmesh_private.h" + +#include "mesh_intern.h" /* own include */ + +#include "tools/bmesh_intersect.h" + + +/* -------------------------------------------------------------------- */ +/* Cut intersections into geometry */ + +/** + * Compare selected with its self. + */ +static int bm_face_isect_self(BMFace *f, void *UNUSED(user_data)) +{ + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + return 0; + } + else { + return -1; + } +} + +/** + * Compare selected/unselected. + */ +static int bm_face_isect_pair(BMFace *f, void *UNUSED(user_data)) +{ + if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + return -1; + } + else if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + return 0; + } + else { + return 1; + } +} + +enum { + ISECT_SEL = 0, + ISECT_SEL_UNSEL = 1, +}; + +static EnumPropertyItem isect_mode_items[] = { + {ISECT_SEL, "SELECT", 0, "Self Intersect", + "Self intersect selected faces"}, + {ISECT_SEL_UNSEL, "SELECT_UNSELECT", 0, "Selected/Unselected", + "Intersect selected with unselected faces"}, + {0, NULL, 0, NULL, NULL} +}; + +static int edbm_intersect_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + const int mode = RNA_enum_get(op->ptr, "mode"); + int (*test_fn)(BMFace *, void *); + bool use_separate = RNA_boolean_get(op->ptr, "use_separate"); + const float eps = RNA_float_get(op->ptr, "threshold"); + bool use_self; + bool has_isect; + + switch (mode) { + case ISECT_SEL: + test_fn = bm_face_isect_self; + use_self = true; + break; + default: /* ISECT_SEL_UNSEL */ + test_fn = bm_face_isect_pair; + use_self = false; + break; + } + + + has_isect = BM_mesh_intersect( + bm, + em->looptris, em->tottri, + test_fn, NULL, + use_self, use_separate, + eps); + + + if (has_isect) { + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); + + if (em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) { + BMIter iter; + BMEdge *e; + + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + BM_edge_select_set(bm, e, true); + } + } + } + + EDBM_mesh_normals_update(em); + EDBM_update_generic(em, true, true); + } + else { + BKE_report(op->reports, RPT_WARNING, "No intersections found"); + } + + return OPERATOR_FINISHED; +} + +void MESH_OT_intersect(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Intersect"; + ot->description = "Cut an intersection into faces"; + ot->idname = "MESH_OT_intersect"; + + /* api callbacks */ + ot->exec = edbm_intersect_exec; + ot->poll = ED_operator_editmesh; + + /* props */ + RNA_def_enum(ot->srna, "mode", isect_mode_items, ISECT_SEL_UNSEL, "Source", ""); + RNA_def_boolean(ot->srna, "use_separate", true, "Separate", ""); + RNA_def_float(ot->srna, "threshold", 0.000001f, 0.0, 0.01, "Merge threshold", "", 0.0, 0.001); + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + + +/* -------------------------------------------------------------------- */ +/* Face Split by Edges */ + + +/** \name Face/Edge Split + * \{ */ + +static void bm_face_split_by_edges(BMesh *bm, BMFace *f, const char hflag) +{ + BMEdge **edge_net = NULL; + BLI_array_declare(edge_net); + + const int f_index = BM_elem_index_get(f); + + BMLoop *l_iter; + BMLoop *l_first; + BMVert *v; + + BMFace **face_arr; + int face_arr_len; + + /* likely this will stay very small + * all verts pushed into this stack _must_ have their previous edges set! */ + BLI_SMALLSTACK_DECLARE(vert_stack, BMVert *); + BLI_SMALLSTACK_DECLARE(vert_stack_next, BMVert *); + + + /* collect all edges */ + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BMIter iter; + BMEdge *e; + + BM_ITER_ELEM (e, &iter, l_iter->v, BM_EDGES_OF_VERT) { + if (BM_elem_flag_test(e, hflag) && + (BM_elem_index_get(e) == f_index)) + { + v = BM_edge_other_vert(e, l_iter->v); + v->e = e; + + BLI_SMALLSTACK_PUSH(vert_stack, v); + BLI_array_append(edge_net, e); + } + } + } while ((l_iter = l_iter->next) != l_first); + + + + /* now assign all */ + /* pop free values into the next stack */ + while ((v = BLI_SMALLSTACK_POP_EX(vert_stack, vert_stack_next))) { + BMIter eiter; + BMEdge *e_next; + + BM_ITER_ELEM (e_next, &eiter, v, BM_EDGES_OF_VERT) { + if (BM_elem_flag_test(e_next, hflag) && + (BM_elem_index_get(e_next) == -1)) + { + BMVert *v_next; + v_next = BM_edge_other_vert(e_next, v); + BM_elem_index_set(e_next, f_index); + BLI_SMALLSTACK_PUSH(vert_stack_next, v_next); + BLI_array_append(edge_net, e_next); + } + } + + if (BLI_SMALLSTACK_IS_EMPTY(vert_stack)) { + BLI_SMALLSTACK_SWAP(vert_stack, vert_stack_next); + } + } + + BM_face_split_edgenet(bm, f, edge_net, BLI_array_count(edge_net), &face_arr, &face_arr_len); + BLI_array_free(edge_net); + + if (face_arr_len) { + int i; + for (i = 0; i < face_arr_len; i++) { + BM_face_select_set(bm, face_arr[i], true); + BM_elem_flag_disable(face_arr[i], hflag); + } + } + + if (face_arr) { + MEM_freeN(face_arr); + } +} + +static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + const char hflag = BM_ELEM_TAG; + + BMVert *v; + BMEdge *e; + BMFace *f; + BMIter iter; + + BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *); + + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + BM_elem_flag_disable(v, hflag); + } + + /* edge index is set to -1 then used to assosiate them with faces */ + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_wire(e)) { + BM_elem_flag_enable(e, hflag); + + BM_elem_flag_enable(e->v1, hflag); + BM_elem_flag_enable(e->v2, hflag); + + } + else { + BM_elem_flag_disable(e, hflag); + } + BM_elem_index_set(e, -1); /* set_dirty */ + } + + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + BM_elem_flag_enable(f, hflag); + } + else { + BM_elem_flag_disable(f, hflag); + } + } + + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, hflag)) { + BMIter viter; + BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) { + BMIter liter; + BMLoop *l; + + unsigned int loop_stack_len; + BMLoop *l_best = NULL; + + BLI_assert(BLI_SMALLSTACK_IS_EMPTY(loop_stack)); + loop_stack_len = 0; + + BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { + if (BM_elem_flag_test(l->f, hflag)) { + BLI_SMALLSTACK_PUSH(loop_stack, l); + loop_stack_len++; + } + } + + if (loop_stack_len == 0) { + /* pass */ + } + else if (loop_stack_len == 1) { + l_best = BLI_SMALLSTACK_POP(loop_stack); + } + else { + /* complicated case, match the edge with a face-loop */ + + BMVert *v_other = BM_edge_other_vert(e, v); + float e_dir[3]; + + /* we wan't closest to zero */ + float dot_best = FLT_MAX; + + sub_v3_v3v3(e_dir, v_other->co, v->co); + normalize_v3(e_dir); + + while ((l = BLI_SMALLSTACK_POP(loop_stack))) { + float dot_test; + + /* Check dot first to save on expensive angle-comparison. + * ideal case is 90d difference == 0.0 dot */ + dot_test = fabsf(dot_v3v3(e_dir, l->f->no)); + if (dot_test < dot_best) { + + /* check we're in the correct corner (works with convex loops too) */ + if (angle_signed_on_axis_v3v3v3_v3(l->prev->v->co, l->v->co, v_other->co, l->f->no) < + angle_signed_on_axis_v3v3v3_v3(l->prev->v->co, l->v->co, l->next->v->co, l->f->no)) + { + dot_best = dot_test; + l_best = l; + } + } + } + } + + if (l_best) { + BM_elem_index_set(e, BM_elem_index_get(l_best->f)); /* set_dirty */ + } + } + } + } + + bm->elem_index_dirty |= BM_EDGE; + + + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, hflag)) { + bm_face_split_by_edges(bm, f, hflag); + } + } + + EDBM_mesh_normals_update(em); + EDBM_update_generic(em, true, true); + + return OPERATOR_FINISHED; +} + + +void MESH_OT_face_split_by_edges(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Split by Edges"; + ot->description = "Split faces by loose edges"; + ot->idname = "MESH_OT_face_split_by_edges"; + + /* api callbacks */ + ot->exec = edbm_face_split_by_edges_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/** \} */ diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 3dc0c85699a..4828fa02d42 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -27,6 +27,8 @@ /** \file blender/editors/mesh/editmesh_knife.c * \ingroup edmesh + * + * Interactive editmesh knife tool. */ #ifdef _MSC_VER @@ -71,13 +73,12 @@ #include "mesh_intern.h" /* own include */ -/* this code here is kindof messy. . .I might need to eventually rework it - joeedh */ - #define KMAXDIST 10 /* max mouse distance from edge before not detecting it */ #define KNIFE_FLT_EPS 0.00001f #define KNIFE_FLT_EPS_SQUARED (KNIFE_FLT_EPS * KNIFE_FLT_EPS) #define KNIFE_FLT_EPSBIG 0.0005f +#define KNIFE_FLT_EPS_PX 0.2f typedef struct KnifeColors { unsigned char line[3]; @@ -115,7 +116,7 @@ typedef struct KnifeEdge { typedef struct KnifeLineHit { float hit[3], cagehit[3]; - float schit[2]; + float schit[2]; /* screen coordinates for cagehit */ float l; /* lambda along cut line */ float perc; /* lambda along hit line */ float m; /* depth front-to-back */ @@ -343,7 +344,7 @@ static KnifeVert *new_knife_vert(KnifeTool_OpData *kcd, const float co[3], const copy_v3_v3(kfv->co, co); copy_v3_v3(kfv->cageco, cageco); - knife_project_v2(kcd, kfv->co, kfv->sco); + knife_project_v2(kcd, kfv->cageco, kfv->sco); return kfv; } @@ -486,21 +487,14 @@ static void knife_edge_append_face(KnifeTool_OpData *kcd, KnifeEdge *kfe, BMFace knife_append_list(kcd, &kfe->faces, f); } -static KnifeVert *knife_split_edge(KnifeTool_OpData *kcd, KnifeEdge *kfe, float co[3], KnifeEdge **newkfe_out) +static KnifeVert *knife_split_edge( + KnifeTool_OpData *kcd, KnifeEdge *kfe, + const float co[3], const float cageco[3], + KnifeEdge **r_kfe) { KnifeEdge *newkfe = new_knife_edge(kcd); Ref *ref; BMFace *f; - float perc, cageco[3], l12; - - l12 = len_v3v3(kfe->v1->co, kfe->v2->co); - if (l12 < KNIFE_FLT_EPS) { - copy_v3_v3(cageco, kfe->v1->cageco); - } - else { - perc = len_v3v3(co, kfe->v1->co) / l12; - interp_v3_v3v3(cageco, kfe->v1->cageco, kfe->v2->cageco, perc); - } newkfe->v1 = kfe->v1; newkfe->v2 = new_knife_vert(kcd, co, cageco); @@ -532,7 +526,7 @@ static KnifeVert *knife_split_edge(KnifeTool_OpData *kcd, KnifeEdge *kfe, float newkfe->draw = kfe->draw; newkfe->e = kfe->e; - *newkfe_out = newkfe; + *r_kfe = newkfe; return newkfe->v2; } @@ -670,7 +664,7 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd, KnifeLineHit *lh1, Knife kfe->v1 = lh1->v; } else if (lh1->kfe) { - kfe->v1 = knife_split_edge(kcd, lh1->kfe, lh1->cagehit, &kfe2); + kfe->v1 = knife_split_edge(kcd, lh1->kfe, lh1->hit, lh1->cagehit, &kfe2); lh1->v = kfe->v1; /* record the KnifeVert for this hit */ } else { @@ -686,7 +680,7 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd, KnifeLineHit *lh1, Knife kfe->v2 = lh2->v; } else if (lh2->kfe) { - kfe->v2 = knife_split_edge(kcd, lh2->kfe, lh2->cagehit, &kfe2); + kfe->v2 = knife_split_edge(kcd, lh2->kfe, lh2->hit, lh2->cagehit, &kfe2); lh2->v = kfe->v2; /* future uses of lh2 won't split again */ } else { @@ -1070,21 +1064,22 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) if (v3d->zbuf) glEnable(GL_DEPTH_TEST); } -/* Find intersection of v1-v2 with face f. - * Only take intersections that are at least face_tol (in screen space) away +/** + * Find intersection of v1-v2 with face f. + * Only take intersections that are at least \a face_tol_sq (in screen space) away * from other intersection elements. * If v1-v2 is coplanar with f, call that "no intersection though * it really means "infinite number of intersections". - * In such a case we should have gotten hits on edges or verts of the face. */ -static bool knife_ray_intersect_face(KnifeTool_OpData *kcd, - const float s[2], - const float v1[3], const float v2[3], - BMFace *f, - const float face_tol, - float intersectp[3]) + * In such a case we should have gotten hits on edges or verts of the face. + */ +static bool knife_ray_intersect_face( + KnifeTool_OpData *kcd, + const float s[2], const float v1[3], const float v2[3], + BMFace *f, const float face_tol_sq, + float hit_co[3], float hit_cageco[3]) { int tottri, tri_i; - float lv1[3], lv2[3], lv3[3], raydir[3]; + float raydir[3]; float tri_norm[3], tri_plane[4]; float se1[2], se2[2]; float d, lambda; @@ -1100,12 +1095,14 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd, BLI_assert(tri_i >= 0 && tri_i < tottri); for (; tri_i < tottri; tri_i++) { + const float *lv1, *lv2, *lv3; + tri = kcd->em->looptris[tri_i]; if (tri[0]->f != f) break; - copy_v3_v3(lv1, kcd->cagecos[BM_elem_index_get(tri[0]->v)]); - copy_v3_v3(lv2, kcd->cagecos[BM_elem_index_get(tri[1]->v)]); - copy_v3_v3(lv3, kcd->cagecos[BM_elem_index_get(tri[2]->v)]); + lv1 = kcd->cagecos[BM_elem_index_get(tri[0]->v)]; + lv2 = kcd->cagecos[BM_elem_index_get(tri[1]->v)]; + lv3 = kcd->cagecos[BM_elem_index_get(tri[2]->v)]; /* using epsilon test in case ray is directly through an internal * tesselation edge and might not hit either tesselation tri with * an exact test; @@ -1114,24 +1111,29 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd, /* check if line coplanar with tri */ normal_tri_v3(tri_norm, lv1, lv2, lv3); plane_from_point_normal_v3(tri_plane, lv1, tri_norm); - if ((fabsf(dist_squared_to_plane_v3(v1, tri_plane)) < KNIFE_FLT_EPS) && - (fabsf(dist_squared_to_plane_v3(v2, tri_plane)) < KNIFE_FLT_EPS)) + if ((dist_squared_to_plane_v3(v1, tri_plane) < KNIFE_FLT_EPS) && + (dist_squared_to_plane_v3(v2, tri_plane) < KNIFE_FLT_EPS)) { return false; } - copy_v3_v3(intersectp, v1); - madd_v3_v3fl(intersectp, raydir, lambda); + copy_v3_v3(hit_cageco, v1); + madd_v3_v3fl(hit_cageco, raydir, lambda); /* Now check that far enough away from verts and edges */ lst = knife_get_face_kedges(kcd, f); for (ref = lst->first; ref; ref = ref->next) { kfe = ref->ref; knife_project_v2(kcd, kfe->v1->cageco, se1); knife_project_v2(kcd, kfe->v2->cageco, se2); - d = dist_to_line_segment_v2(s, se1, se2); - if (d < face_tol) { + d = dist_squared_to_line_segment_v2(s, se1, se2); + if (d < face_tol_sq) { return false; } } + + transform_point_by_tri_v3( + hit_co, hit_cageco, + tri[0]->v->co, tri[1]->v->co, tri[2]->v->co, + lv1, lv2, lv3); return true; } } @@ -1221,16 +1223,7 @@ static void clip_to_ortho_planes(float v1[3], float v2[3], float d) static void set_linehit_depth(KnifeTool_OpData *kcd, KnifeLineHit *lh) { - float vnear[3], vfar[3]; - - ED_view3d_win_to_segment(kcd->ar, kcd->vc.v3d, lh->schit, vnear, vfar, true); - mul_m4_v3(kcd->ob->imat, vnear); - if (kcd->is_ortho && (kcd->vc.rv3d->persp != RV3D_CAMOB)) { - if (kcd->ortho_extent == 0.0f) - calc_ortho_extent(kcd); - clip_to_ortho_planes(vnear, vfar, kcd->ortho_extent + 10.0f); - } - lh->m = len_v3v3(vnear, lh->cagehit); + lh->m = dot_m4_v3_row_z(kcd->vc.rv3d->persmatob, lh->cagehit); } /* Finds visible (or all, if cutting through) edges that intersects the current screen drag line */ @@ -1254,9 +1247,12 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) void *val; float plane_cos[12]; float s[2], se1[2], se2[2], sint[2]; - float p[3], p2[3], r1[3], r2[3]; + float r1[3], r2[3]; float d, d1, d2, lambda; - float vert_tol, vert_tol_sq, line_tol, face_tol; + float vert_tol, vert_tol_sq; + float line_tol, line_tol_sq; + float face_tol, face_tol_sq; + float eps_scale; int isect_kind; unsigned int tot; int i; @@ -1359,10 +1355,22 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) /* Now go through the candidates and find intersections */ /* These tolerances, in screen space, are for intermediate hits, as ends are already snapped to screen */ - vert_tol = KNIFE_FLT_EPS * 2000.0f; - line_tol = KNIFE_FLT_EPS * 2000.0f; - vert_tol_sq = vert_tol * vert_tol; + { + /* Scale the epsilon by the zoom level + * to compensate for projection imprecision, see T41164 */ + float zoom_xy[2] = {kcd->vc.rv3d->winmat[0][0], + kcd->vc.rv3d->winmat[1][1]}; + eps_scale = len_v2(zoom_xy); + } + + vert_tol = KNIFE_FLT_EPS_PX * eps_scale; + line_tol = KNIFE_FLT_EPS_PX * eps_scale; face_tol = max_ff(vert_tol, line_tol); + + vert_tol_sq = vert_tol * vert_tol; + line_tol_sq = line_tol * line_tol; + face_tol_sq = face_tol * face_tol; + /* Assume these tolerances swamp floating point rounding errors in calculations below */ /* first look for vertex hits */ @@ -1375,7 +1383,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) if (point_is_visible(kcd, v->cageco, s, &mats)) { memset(&hit, 0, sizeof(hit)); hit.v = v; - copy_v3_v3(hit.hit, v->cageco); + copy_v3_v3(hit.hit, v->co); copy_v3_v3(hit.cagehit, v->cageco); copy_v2_v2(hit.schit, s); set_linehit_depth(kcd, &hit); @@ -1393,35 +1401,39 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) if (isect_kind == -1) { /* isect_seg_seg_v2 doesn't do tolerance test around ends of s1-s2 */ closest_to_line_segment_v2(sint, s1, se1, se2); - if (len_squared_v2v2(sint, s1) <= vert_tol_sq) + if (len_squared_v2v2(sint, s1) <= line_tol_sq) isect_kind = 1; else { closest_to_line_segment_v2(sint, s2, se1, se2); - if (len_squared_v2v2(sint, s2) <= vert_tol_sq) + if (len_squared_v2v2(sint, s2) <= line_tol_sq) isect_kind = 1; } } if (isect_kind == 1) { d1 = len_v2v2(sint, se1); d2 = len_v2v2(se2, se1); - if (!(d1 <= vert_tol || d2 <= vert_tol || fabsf(d1 - d2) <= vert_tol)) { + if (!(d1 <= line_tol || d2 <= line_tol || fabsf(d1 - d2) <= line_tol)) { + float p_cage[3], p_cage_tmp[3]; lambda = d1 / d2; /* Can't just interpolate between ends of kfe because * that doesn't work with perspective transformation. * Need to find 3d intersection of ray through sint */ knife_input_ray_segment(kcd, sint, 1.0f, r1, r2); - isect_kind = isect_line_line_v3(kfe->v1->cageco, kfe->v2->cageco, r1, r2, p, p2); - if (isect_kind >= 1 && point_is_visible(kcd, p, sint, &mats)) { + isect_kind = isect_line_line_v3(kfe->v1->cageco, kfe->v2->cageco, r1, r2, p_cage, p_cage_tmp); + if (isect_kind >= 1 && point_is_visible(kcd, p_cage, sint, &mats)) { memset(&hit, 0, sizeof(hit)); if (kcd->snap_midpoints) { /* choose intermediate point snap too */ - mid_v3_v3v3(p, kfe->v1->cageco, kfe->v2->cageco); + mid_v3_v3v3(p_cage, kfe->v1->cageco, kfe->v2->cageco); mid_v2_v2v2(sint, se1, se2); lambda = 0.5f; } hit.kfe = kfe; - copy_v3_v3(hit.hit, p); - copy_v3_v3(hit.cagehit, p); + transform_point_by_seg_v3( + hit.hit, p_cage, + kfe->v1->co, kfe->v2->co, + kfe->v1->cageco, kfe->v2->cageco); + copy_v3_v3(hit.cagehit, p_cage); copy_v2_v2(hit.schit, sint); hit.perc = lambda; set_linehit_depth(kcd, &hit); @@ -1434,23 +1446,25 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) for (val = BLI_smallhash_iternew(&faces, &hiter, (uintptr_t *)&f); val; val = BLI_smallhash_iternext(&hiter, (uintptr_t *)&f)) { - if (knife_ray_intersect_face(kcd, s1, v1, v3, f, face_tol, p)) { - if (point_is_visible(kcd, p, s1, &mats)) { + float p[3], p_cage[3]; + + if (knife_ray_intersect_face(kcd, s1, v1, v3, f, face_tol_sq, p, p_cage)) { + if (point_is_visible(kcd, p_cage, s1, &mats)) { memset(&hit, 0, sizeof(hit)); hit.f = f; copy_v3_v3(hit.hit, p); - copy_v3_v3(hit.cagehit, p); + copy_v3_v3(hit.cagehit, p_cage); copy_v2_v2(hit.schit, s1); set_linehit_depth(kcd, &hit); BLI_array_append(linehits, hit); } } - if (knife_ray_intersect_face(kcd, s2, v2, v4, f, face_tol, p)) { - if (point_is_visible(kcd, p, s2, &mats)) { + if (knife_ray_intersect_face(kcd, s2, v2, v4, f, face_tol_sq, p, p_cage)) { + if (point_is_visible(kcd, p_cage, s2, &mats)) { memset(&hit, 0, sizeof(hit)); hit.f = f; copy_v3_v3(hit.hit, p); - copy_v3_v3(hit.cagehit, p); + copy_v3_v3(hit.cagehit, p_cage); copy_v2_v2(hit.schit, s2); set_linehit_depth(kcd, &hit); BLI_array_append(linehits, hit); @@ -1858,7 +1872,7 @@ static int knife_update_active(KnifeTool_OpData *kcd) copy_v2_v2(kcd->curr.mval, kcd->mval); /* view matrix may have changed, reproject */ - knife_project_v2(kcd, kcd->prev.co, kcd->prev.mval); + knife_project_v2(kcd, kcd->prev.cage, kcd->prev.mval); if (kcd->angle_snapping != ANGLE_FREE && kcd->mode == MODE_DRAGGING) { kcd->is_angle_snapping = knife_snap_angle(kcd); @@ -2252,31 +2266,28 @@ static bool find_hole_chains(KnifeTool_OpData *kcd, ListBase *hole, BMFace *f, L static bool knife_verts_edge_in_face(KnifeVert *v1, KnifeVert *v2, BMFace *f) { - BMLoop *l1, *l2, *l; - float mid[3]; - BMIter iter; - int v1inside, v2inside; + bool v1_inside, v2_inside; + bool v1_inface, v2_inface; if (!f || !v1 || !v2) return false; - l1 = NULL; - l2 = NULL; - /* find out if v1 and v2, if set, are part of the face */ - BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) { - if (v1->v && l->v == v1->v) - l1 = l; - if (v2->v && l->v == v2->v) - l2 = l; - } + v1_inface = v1->v ? BM_vert_in_face(f, v1->v) : false; + v2_inface = v2->v ? BM_vert_in_face(f, v2->v) : false; /* BM_face_point_inside_test uses best-axis projection so this isn't most accurate test... */ - v1inside = l1 ? 0 : BM_face_point_inside_test(f, v1->co); - v2inside = l2 ? 0 : BM_face_point_inside_test(f, v2->co); - if ((l1 && v2inside) || (l2 && v1inside) || (v1inside && v2inside)) + v1_inside = v1_inface ? false : BM_face_point_inside_test(f, v1->co); + v2_inside = v2_inface ? false : BM_face_point_inside_test(f, v2->co); + if ((v1_inface && v2_inside) || + (v2_inface && v1_inside) || + (v1_inside && v2_inside)) + { return true; - if (l1 && l2) { + } + + if (v1_inface && v2_inface) { + float mid[3]; /* Can have case where v1 and v2 are on shared chain between two faces. * BM_face_splits_check_legal does visibility and self-intersection tests, * but it is expensive and maybe a bit buggy, so use a simple @@ -2375,12 +2386,12 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfe KnifeEdge *kfe; BMFace *fnew, *fnew2, *fhole; ListBase *chain, *hole, *sidechain; - ListBase *fnew_kfedges, *fnew2_kfedges; Ref *ref, *refnext; int count, oldcount; oldcount = BLI_countlist(kfedges); while ((chain = find_chain(kcd, kfedges)) != NULL) { + ListBase fnew_kfedges; knife_make_chain_cut(kcd, f, chain, &fnew); if (!fnew) { return; @@ -2388,18 +2399,22 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfe /* Move kfedges to fnew_kfedges if they are now in fnew. * The chain edges were removed already */ - fnew_kfedges = knife_empty_list(kcd); + BLI_listbase_clear(&fnew_kfedges); for (ref = kfedges->first; ref; ref = refnext) { kfe = ref->ref; refnext = ref->next; if (knife_edge_in_face(kfe, fnew)) { BLI_remlink(kfedges, ref); kfe->basef = fnew; - knife_append_list(kcd, fnew_kfedges, kfe); + BLI_addtail(&fnew_kfedges, ref); + } + else if (!knife_edge_in_face(kfe, f)) { + /* Concave ngon's - this edge might not be in either faces, T41730 */ + BLI_remlink(kfedges, ref); } } - if (fnew_kfedges->first) - knife_make_face_cuts(kcd, fnew, fnew_kfedges); + if (fnew_kfedges.first) + knife_make_face_cuts(kcd, fnew, &fnew_kfedges); /* find_chain should always remove edges if it returns true, * but guard against infinite loop anyway */ @@ -2413,6 +2428,8 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfe while ((hole = find_hole(kcd, kfedges)) != NULL) { if (find_hole_chains(kcd, hole, f, &chain, &sidechain)) { + ListBase fnew_kfedges, fnew2_kfedges; + /* chain goes across f and sidechain comes back * from the second last vertex to the second vertex. */ @@ -2443,28 +2460,28 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfe BM_face_kill(bm, fhole); /* Move kfedges to either fnew or fnew2 if appropriate. * The hole edges were removed already */ - fnew_kfedges = knife_empty_list(kcd); - fnew2_kfedges = knife_empty_list(kcd); + BLI_listbase_clear(&fnew_kfedges); + BLI_listbase_clear(&fnew2_kfedges); for (ref = kfedges->first; ref; ref = refnext) { kfe = ref->ref; refnext = ref->next; if (knife_edge_in_face(kfe, fnew)) { BLI_remlink(kfedges, ref); kfe->basef = fnew; - knife_append_list(kcd, fnew_kfedges, kfe); + BLI_addtail(&fnew_kfedges, ref); } else if (knife_edge_in_face(kfe, fnew2)) { BLI_remlink(kfedges, ref); kfe->basef = fnew2; - knife_append_list(kcd, fnew2_kfedges, kfe); + BLI_addtail(&fnew2_kfedges, ref); } } /* We'll skip knife edges that are in the newly formed hole. * (Maybe we shouldn't have made a hole in the first place?) */ - if (fnew != fhole && fnew_kfedges->first) - knife_make_face_cuts(kcd, fnew, fnew_kfedges); - if (fnew2 != fhole && fnew2_kfedges->first) - knife_make_face_cuts(kcd, fnew2, fnew2_kfedges); + if (fnew != fhole && fnew_kfedges.first) + knife_make_face_cuts(kcd, fnew, &fnew_kfedges); + if (fnew2 != fhole && fnew2_kfedges.first) + knife_make_face_cuts(kcd, fnew2, &fnew2_kfedges); if (f == fhole) break; /* find_hole should always remove edges if it returns true, diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c index cc26d6079a9..553c1faa36a 100644 --- a/source/blender/editors/mesh/editmesh_knife_project.c +++ b/source/blender/editors/mesh/editmesh_knife_project.c @@ -65,7 +65,7 @@ static LinkNode *knifeproject_poly_from_object(ARegion *ar, Scene *scene, Object dm = ob->derivedFinal ? ob->derivedFinal : mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); dm_needsFree = false; } - else if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { + else if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { dm = CDDM_from_curve(ob); dm_needsFree = true; } diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c index bb044f39fba..59fbe739d03 100644 --- a/source/blender/editors/mesh/editmesh_loopcut.c +++ b/source/blender/editors/mesh/editmesh_loopcut.c @@ -555,39 +555,27 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event) int cuts = RNA_int_get(op->ptr, "number_cuts"); RingSelOpData *lcd = op->customdata; bool show_cuts = false; + const bool has_numinput = hasNumInput(&lcd->num); view3d_operator_needs_opengl(C); /* using the keyboard to input the number of cuts */ - if (event->val == KM_PRESS && hasNumInput(&lcd->num)) { - /* Modal numinput active, try to handle numeric inputs first... */ - if (handleNumInput(C, &lcd->num, event)) { - float values[2] = {(float)cuts, smoothness}; - applyNumInput(&lcd->num, values); - - /* allow zero so you can backspace and type in a value - * otherwise 1 as minimum would make more sense */ - cuts = CLAMPIS(values[0], 0, SUBD_CUTS_MAX); - smoothness = CLAMPIS(values[1], -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX); - - RNA_int_set(op->ptr, "number_cuts", cuts); - ringsel_find_edge(lcd, cuts); - show_cuts = true; - RNA_float_set(op->ptr, "smoothness", smoothness); - - ED_region_tag_redraw(lcd->ar); - } - else { - switch (event->type) { - case RETKEY: - case PADENTER: - case LEFTMOUSE: /* confirm */ // XXX hardcoded - return loopcut_finish(lcd, C, op); - default: - /* do nothing */; - break; - } - } + /* Modal numinput active, try to handle numeric inputs first... */ + if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &lcd->num, event)) { + float values[2] = {(float)cuts, smoothness}; + applyNumInput(&lcd->num, values); + + /* allow zero so you can backspace and type in a value + * otherwise 1 as minimum would make more sense */ + cuts = CLAMPIS(values[0], 0, SUBD_CUTS_MAX); + smoothness = CLAMPIS(values[1], -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX); + + RNA_int_set(op->ptr, "number_cuts", cuts); + ringsel_find_edge(lcd, cuts); + show_cuts = true; + RNA_float_set(op->ptr, "smoothness", smoothness); + + ED_region_tag_redraw(lcd->ar); } else { bool handled = false; @@ -663,35 +651,33 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event) handled = true; break; case MOUSEMOVE: /* mouse moved somewhere to select another loop */ - { - lcd->vc.mval[0] = event->mval[0]; - lcd->vc.mval[1] = event->mval[1]; - loopcut_mouse_move(lcd, cuts); + if (!has_numinput) { + lcd->vc.mval[0] = event->mval[0]; + lcd->vc.mval[1] = event->mval[1]; + loopcut_mouse_move(lcd, cuts); - ED_region_tag_redraw(lcd->ar); - handled = true; + ED_region_tag_redraw(lcd->ar); + handled = true; + } break; - } } - if (!handled && event->val == KM_PRESS) { - /* Modal numinput inactive, try to handle numeric inputs last... */ - if (handleNumInput(C, &lcd->num, event)) { - float values[2] = {(float)cuts, smoothness}; - applyNumInput(&lcd->num, values); - - /* allow zero so you can backspace and type in a value - * otherwise 1 as minimum would make more sense */ - cuts = CLAMPIS(values[0], 0, SUBD_CUTS_MAX); - smoothness = CLAMPIS(values[1], -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX); - - RNA_int_set(op->ptr, "number_cuts", cuts); - ringsel_find_edge(lcd, cuts); - show_cuts = true; - RNA_float_set(op->ptr, "smoothness", smoothness); - - ED_region_tag_redraw(lcd->ar); - } + /* Modal numinput inactive, try to handle numeric inputs last... */ + if (!handled && event->val == KM_PRESS && handleNumInput(C, &lcd->num, event)) { + float values[2] = {(float)cuts, smoothness}; + applyNumInput(&lcd->num, values); + + /* allow zero so you can backspace and type in a value + * otherwise 1 as minimum would make more sense */ + cuts = CLAMPIS(values[0], 0, SUBD_CUTS_MAX); + smoothness = CLAMPIS(values[1], -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX); + + RNA_int_set(op->ptr, "number_cuts", cuts); + ringsel_find_edge(lcd, cuts); + show_cuts = true; + RNA_float_set(op->ptr, "smoothness", smoothness); + + ED_region_tag_redraw(lcd->ar); } } @@ -700,7 +686,7 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event) char buf[64 + NUM_STR_REP_LEN * 2]; char str_rep[NUM_STR_REP_LEN * 2]; if (hasNumInput(&lcd->num)) { - outputNumInput(&lcd->num, str_rep, sce->unit.scale_length); + outputNumInput(&lcd->num, str_rep, &sce->unit); } else { BLI_snprintf(str_rep, NUM_STR_REP_LEN, "%d", cuts); diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c index 3d3e41d31cc..3b993332db0 100644 --- a/source/blender/editors/mesh/editmesh_rip.c +++ b/source/blender/editors/mesh/editmesh_rip.c @@ -993,6 +993,12 @@ static int edbm_rip_invoke(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_CANCELLED; } + /* we could support this, but not for now */ + if ((bm->totvertsel > 1) && (bm->totedgesel == 0)) { + BKE_report(op->reports, RPT_ERROR, "Cannot rip multiple disconnected vertices"); + return OPERATOR_CANCELLED; + } + /* note on selection: * When calling edge split we operate on tagged edges rather then selected * this is important because the edges to operate on are extended by one, diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 23828098940..9cdfb43ae15 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -2807,6 +2807,13 @@ static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op) BMEdge *e; BMIter iter; + const bool use_wire = RNA_boolean_get(op->ptr, "use_wire"); + const bool use_boundary = RNA_boolean_get(op->ptr, "use_boundary"); + const bool use_multi_face = RNA_boolean_get(op->ptr, "use_multi_face"); + const bool use_non_contiguous = RNA_boolean_get(op->ptr, "use_non_contiguous"); + const bool use_verts = RNA_boolean_get(op->ptr, "use_verts"); + + if (!RNA_boolean_get(op->ptr, "extend")) EDBM_flag_disable_all(em, BM_ELEM_SELECT); @@ -2819,15 +2826,30 @@ static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { - if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN) && !BM_vert_is_manifold(v)) { - BM_vert_select_set(em->bm, v, true); + if (use_verts) { + BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { + if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { + if (!BM_vert_is_manifold(v)) { + BM_vert_select_set(em->bm, v, true); + } + } } } - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && !BM_edge_is_manifold(e)) { - BM_edge_select_set(em->bm, e, true); + if (use_wire || use_boundary || use_multi_face || use_non_contiguous) { + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { + if ((use_wire && BM_edge_is_wire(e)) || + (use_boundary && BM_edge_is_boundary(e)) || + (use_non_contiguous && (BM_edge_is_manifold(e) && !BM_edge_is_contiguous(e))) || + (use_multi_face && (BM_edge_face_count(e) > 2))) + { + /* check we never select perfect edge (in test above) */ + BLI_assert(!(BM_edge_is_manifold(e) && BM_edge_is_contiguous(e))); + + BM_edge_select_set(em->bm, e, true); + } + } } } @@ -2854,6 +2876,18 @@ void MESH_OT_select_non_manifold(wmOperatorType *ot) /* props */ RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend the selection"); + /* edges */ + RNA_def_boolean(ot->srna, "use_wire", true, "Wire", + "Wire edges"); + RNA_def_boolean(ot->srna, "use_boundary", true, "Boundaries", + "Boundary edges"); + RNA_def_boolean(ot->srna, "use_multi_face", true, + "Multiple Faces", "Edges shared by 3+ faces"); + RNA_def_boolean(ot->srna, "use_non_contiguous", true, "Non Contiguous", + "Edges between faces pointing in alternate directions"); + /* verts */ + RNA_def_boolean(ot->srna, "use_verts", true, "Vertices", + "Vertices connecting multiple face regions"); } static int edbm_select_random_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 55ad303d0e1..3f1023b7fb4 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -881,12 +881,18 @@ static int edbm_vert_connect_exec(bContext *C, wmOperator *op) int len; if (is_pair) { - if (!EDBM_op_init(em, &bmop, op, "connect_vert_pair verts=%hv", BM_ELEM_SELECT)) { + 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)) + { return OPERATOR_CANCELLED; } } else { - if (!EDBM_op_init(em, &bmop, op, "connect_verts verts=%hv check_degenerate=%b", BM_ELEM_SELECT, true)) { + if (!EDBM_op_init(em, &bmop, op, + "connect_verts verts=%hv faces_exclude=%hf check_degenerate=%b", + BM_ELEM_SELECT, BM_ELEM_HIDDEN, true)) + { return OPERATOR_CANCELLED; } } @@ -1019,28 +1025,23 @@ static int edbm_duplicate_exec(bContext *C, wmOperator *op) BMEditMesh *em = BKE_editmesh_from_object(ob); BMesh *bm = em->bm; BMOperator bmop; - ListBase bm_selected_store = {NULL, NULL}; - /* de-select all would clear otherwise */ - SWAP(ListBase, bm->selected, bm_selected_store); + EDBM_op_init( + em, &bmop, op, + "duplicate geom=%hvef use_select_history=%b", + BM_ELEM_SELECT, true); - EDBM_op_init(em, &bmop, op, "duplicate geom=%hvef", BM_ELEM_SELECT); - BMO_op_exec(bm, &bmop); + + /* de-select all would clear otherwise */ + BM_SELECT_HISTORY_BACKUP(bm); + EDBM_flag_disable_all(em, BM_ELEM_SELECT); BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true); /* rebuild editselection */ - bm->selected = bm_selected_store; - - if (bm->selected.first) { - BMOpSlot *slot_vert_map_out = BMO_slot_get(bmop.slots_out, "vert_map.out"); - BMOpSlot *slot_edge_map_out = BMO_slot_get(bmop.slots_out, "edge_map.out"); - BMOpSlot *slot_face_map_out = BMO_slot_get(bmop.slots_out, "face_map.out"); - - BMO_mesh_selected_remap(bm, slot_vert_map_out, slot_edge_map_out, slot_face_map_out); - } + BM_SELECT_HISTORY_RESTORE(bm); if (!EDBM_op_finish(em, &bmop, op, true)) { return OPERATOR_CANCELLED; @@ -2424,7 +2425,7 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op) float (*screen_vert_coords)[2], (*sco)[2], (*mouse_path)[2]; /* edit-object needed for matrix, and ar->regiondata for projections to work */ - if (ELEM3(NULL, obedit, ar, ar->regiondata)) + if (ELEM(NULL, obedit, ar, ar->regiondata)) return OPERATOR_CANCELLED; if (bm->totvertsel < 2) { @@ -3047,7 +3048,7 @@ static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span } /* set this vertex first */ - BLI_rotatelist_first(verts, v_act_link); + BLI_listbase_rotate_first(verts, v_act_link); BM_edgeloop_edges_get(el_store, edges); @@ -3479,6 +3480,11 @@ static void edbm_dissolve_prop__use_face_split(wmOperatorType *ot) RNA_def_boolean(ot->srna, "use_face_split", 0, "Face Split", "Split off face corners to maintain surrounding geometry"); } +static void edbm_dissolve_prop__use_boundary_tear(wmOperatorType *ot) +{ + RNA_def_boolean(ot->srna, "use_boundary_tear", 0, "Tear Boundary", + "Split off face corners instead of merging faces"); +} static int edbm_dissolve_verts_exec(bContext *C, wmOperator *op) { @@ -3486,9 +3492,14 @@ static int edbm_dissolve_verts_exec(bContext *C, wmOperator *op) BMEditMesh *em = BKE_editmesh_from_object(obedit); const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split"); + const bool use_boundary_tear = RNA_boolean_get(op->ptr, "use_boundary_tear"); - if (!EDBM_op_callf(em, op, "dissolve_verts verts=%hv use_face_split=%b", BM_ELEM_SELECT, use_face_split)) + if (!EDBM_op_callf(em, op, + "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b", + BM_ELEM_SELECT, use_face_split, use_boundary_tear)) + { return OPERATOR_CANCELLED; + } EDBM_update_generic(em, true, true); @@ -3510,6 +3521,7 @@ void MESH_OT_dissolve_verts(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; edbm_dissolve_prop__use_face_split(ot); + edbm_dissolve_prop__use_boundary_tear(ot); } static int edbm_dissolve_edges_exec(bContext *C, wmOperator *op) @@ -3621,6 +3633,7 @@ void MESH_OT_dissolve_mode(wmOperatorType *ot) edbm_dissolve_prop__use_verts(ot); edbm_dissolve_prop__use_face_split(ot); + edbm_dissolve_prop__use_boundary_tear(ot); } static int edbm_dissolve_limited_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 8adaae5fe42..c7d1d883537 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -1328,6 +1328,15 @@ void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_d /* don't keep stale derivedMesh data around, see: [#38872] */ BKE_editmesh_free_derivedmesh(em); + +#ifdef DEBUG + { + BMEditSelection *ese; + for (ese = em->bm->selected.first; ese; ese = ese->next) { + BLI_assert(BM_elem_flag_test(ese->ele, BM_ELEM_SELECT)); + } + } +#endif } /* poll call for mesh operators requiring a view3d context */ diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index 83947534d06..bf8559add6f 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -880,17 +880,6 @@ static void mesh_add_verts(Mesh *mesh, int len) mesh->totvert = totvert; } -void ED_mesh_transform(Mesh *me, float mat[4][4]) -{ - int i; - MVert *mvert = me->mvert; - - for (i = 0; i < me->totvert; i++, mvert++) - mul_m4_v3(mat, mvert->co); - - /* don't update normals, caller can do this explicitly */ -} - static void mesh_add_edges(Mesh *mesh, int len) { CustomData edata; diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index 655d96ae6e5..76f6cb5ebb8 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -112,6 +112,10 @@ void MESH_OT_screw(struct wmOperatorType *ot); /* *** editmesh_inset.c *** */ void MESH_OT_inset(struct wmOperatorType *ot); +/* *** editmesh_intersect.c *** */ +void MESH_OT_intersect(struct wmOperatorType *ot); +void MESH_OT_face_split_by_edges(struct wmOperatorType *ot); + /* *** editmesh_knife.c *** */ void MESH_OT_knife_tool(struct wmOperatorType *ot); diff --git a/source/blender/editors/mesh/mesh_navmesh.c b/source/blender/editors/mesh/mesh_navmesh.c index 433fd176217..440ab14dacd 100644 --- a/source/blender/editors/mesh/mesh_navmesh.c +++ b/source/blender/editors/mesh/mesh_navmesh.c @@ -407,7 +407,7 @@ static Object *createRepresentation(bContext *C, struct recast_polyMesh *pmesh, BM_vert_at_index(em->bm, face[0]), BM_vert_at_index(em->bm, face[2]), BM_vert_at_index(em->bm, face[1]), NULL, - NULL, false); + NULL, BM_CREATE_NOP); /* set navigation polygon idx to the custom layer */ polygonIdx = (int *)CustomData_bmesh_get(&em->bm->pdata, newFace->head.data, CD_RECAST); diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 0f65ed2c4ad..31653efa735 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -170,6 +170,8 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_bridge_edge_loops); WM_operatortype_append(MESH_OT_inset); + WM_operatortype_append(MESH_OT_intersect); + WM_operatortype_append(MESH_OT_face_split_by_edges); WM_operatortype_append(MESH_OT_poke); WM_operatortype_append(MESH_OT_wireframe); WM_operatortype_append(MESH_OT_edge_split); |