From f8611bac8f805974d71501b323ec4a8adf9405d0 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 20 Mar 2013 16:03:34 +0000 Subject: [PATCH] - add knife project to toolbar. - when running knife project, disable vertex selection since it may select areas between the newly cut regions. add EDBM_selectmode_disable() function since loopcut does this too. - (optimization) avoid looping over all geometry when flushing and no selection exists. --- .../startup/bl_ui/space_view3d_toolbar.py | 1 + source/blender/editors/include/ED_mesh.h | 3 + .../editors/mesh/editmesh_knife_project.c | 8 +- .../blender/editors/mesh/editmesh_loopcut.c | 12 +-- source/blender/editors/mesh/editmesh_select.c | 98 +++++++++++++++---- 5 files changed, 91 insertions(+), 31 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 2e98cb68eb5..24e4dac4ded 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -180,6 +180,7 @@ class VIEW3D_PT_tools_meshedit(View3DPanel, Panel): props = row.operator("mesh.knife_tool", text="Select") props.use_occlude_geometry = False props.only_selected = True + col.operator("mesh.knife_project") col = layout.column(align=True) col.label(text="Remove:") diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 7257011e28a..8d389946e4a 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -161,6 +161,9 @@ void EDBM_selectmode_convert(struct BMEditMesh *em, const short selectmode_old, bool EDBM_selectmode_toggle(struct bContext *C, const short selectmode_new, const int action, const bool use_extend, const bool use_expand); +bool EDBM_selectmode_disable(struct Scene *scene, struct BMEditMesh *em, + const short selectmode_disable, + const short selectmode_fallback); void EDBM_deselect_by_material(struct BMEditMesh *em, const short index, const short select); diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c index c581ce5a2e8..0903dd54208 100644 --- a/source/blender/editors/mesh/editmesh_knife_project.c +++ b/source/blender/editors/mesh/editmesh_knife_project.c @@ -51,6 +51,7 @@ #include "WM_types.h" +#include "ED_mesh.h" #include "ED_screen.h" #include "ED_view3d.h" @@ -137,6 +138,12 @@ static int knifeproject_exec(bContext *C, wmOperator *op) /* select only tagged faces */ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); + + /* note essential, but switch out of vertex mode since the + * selected regions wont be nicely isolated after flushing. + * note: call after de-select to avoid selection flushing */ + EDBM_selectmode_disable(scene, em, SCE_SELECT_VERTEX, SCE_SELECT_EDGE); + BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, BM_ELEM_TAG); BM_mesh_select_mode_flush(em->bm); @@ -165,4 +172,3 @@ void MESH_OT_knife_project(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; } - diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c index 89bfc315094..ee1c274b154 100644 --- a/source/blender/editors/mesh/editmesh_loopcut.c +++ b/source/blender/editors/mesh/editmesh_loopcut.c @@ -300,17 +300,11 @@ static void ringsel_finish(bContext *C, wmOperator *op) EDBM_update_generic(em, false, true); /* force edge slide to edge select mode in in face select mode */ - if (em->selectmode & SCE_SELECT_FACE) { - if (em->selectmode == SCE_SELECT_FACE) - em->selectmode = SCE_SELECT_EDGE; - else - em->selectmode &= ~SCE_SELECT_FACE; - CTX_data_tool_settings(C)->selectmode = em->selectmode; - EDBM_selectmode_set(em); - - WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, CTX_data_scene(C)); + if (EDBM_selectmode_disable(lcd->vc.scene, em, SCE_SELECT_FACE, SCE_SELECT_EDGE)) { + /* pass, the change will flush selection */ } else { + /* else flush explicitly */ EDBM_selectmode_flush(lcd->em); } } diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 449ab45da69..947ee240e0d 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -1946,38 +1946,57 @@ void EDBM_selectmode_set(BMEditMesh *em) edbm_strip_selections(em); /* strip BMEditSelections from em->selected that are not relevant to new mode */ + if (em->bm->totvertsel == 0 && + em->bm->totedgesel == 0 && + em->bm->totfacesel == 0) + { + return; + } + if (em->selectmode & SCE_SELECT_VERTEX) { - EDBM_select_flush(em); + if (em->bm->totvertsel) { + EDBM_select_flush(em); + } } else if (em->selectmode & SCE_SELECT_EDGE) { /* deselect vertices, and select again based on edge select */ - eve = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL); - for (; eve; eve = BM_iter_step(&iter)) BM_vert_select_set(em->bm, eve, false); - - eed = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL); - for (; eed; eed = BM_iter_step(&iter)) { - if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { - BM_edge_select_set(em->bm, eed, true); - } + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + BM_vert_select_set(em->bm, eve, false); + } + + if (em->bm->totedgesel) { + BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { + BM_edge_select_set(em->bm, eed, true); + } + } + + /* selects faces based on edge status */ + EDBM_selectmode_flush(em); } - - /* selects faces based on edge status */ - EDBM_selectmode_flush(em); } else if (em->selectmode & SCE_SELECT_FACE) { /* deselect eges, and select again based on face select */ - eed = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL); - for (; eed; eed = BM_iter_step(&iter)) BM_edge_select_set(em->bm, eed, false); - - efa = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL); - for (; efa; efa = BM_iter_step(&iter)) { - if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { - BM_face_select_set(em->bm, efa, true); + BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { + BM_edge_select_set(em->bm, eed, false); + } + + if (em->bm->totfacesel) { + efa = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL); + for (; efa; efa = BM_iter_step(&iter)) { + if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + BM_face_select_set(em->bm, efa, true); + } } } } } +/** + * Flush the selection up: + * - vert -> edge + * - edge -> face + */ void EDBM_selectmode_convert(BMEditMesh *em, const short selectmode_old, const short selectmode_new) { BMEdge *eed; @@ -1988,7 +2007,10 @@ void EDBM_selectmode_convert(BMEditMesh *em, const short selectmode_old, const s /* have to find out what the selectionmode was previously */ if (selectmode_old == SCE_SELECT_VERTEX) { - if (selectmode_new == SCE_SELECT_EDGE) { + if (em->bm->totvertsel == 0) { + /* pass */ + } + else if (selectmode_new == SCE_SELECT_EDGE) { /* select all edges associated with every selected vert */ BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { BM_elem_flag_set(eed, BM_ELEM_TAG, BM_edge_is_any_vert_flag_test(eed, BM_ELEM_SELECT)); @@ -2014,7 +2036,10 @@ void EDBM_selectmode_convert(BMEditMesh *em, const short selectmode_old, const s } } else if (selectmode_old == SCE_SELECT_EDGE) { - if (selectmode_new == SCE_SELECT_FACE) { + if (em->bm->totedgesel == 0) { + /* pass */ + } + else if (selectmode_new == SCE_SELECT_FACE) { /* select all faces associated with every selected edge */ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { BM_elem_flag_set(efa, BM_ELEM_TAG, BM_face_is_any_edge_flag_test(efa, BM_ELEM_SELECT)); @@ -2125,6 +2150,37 @@ bool EDBM_selectmode_toggle(bContext *C, const short selectmode_new, return ret; } +/** + * Use to disable a selectmode if its enabled, Using another mode as a fallback + * if the disabled mode is the only mode set. + * + * \return true if the mode is changed. + */ +bool EDBM_selectmode_disable(Scene *scene, BMEditMesh *em, + const short selectmode_disable, + const short selectmode_fallback) +{ + /* note essential, but switch out of vertex mode since the + * selected regions wont be nicely isolated after flushing */ + if (em->selectmode & selectmode_disable) { + if (em->selectmode == selectmode_disable) { + em->selectmode = selectmode_fallback; + } + else { + em->selectmode &= ~selectmode_disable; + } + scene->toolsettings->selectmode = em->selectmode; + EDBM_selectmode_set(em); + + WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, scene); + + return true; + } + else { + return false; + } +} + void EDBM_deselect_by_material(BMEditMesh *em, const short index, const short select) { BMIter iter;