diff options
Diffstat (limited to 'source/blender/editors/mesh/editmesh_select.c')
-rw-r--r-- | source/blender/editors/mesh/editmesh_select.c | 521 |
1 files changed, 352 insertions, 169 deletions
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index a6de1b284b7..019aa6d4201 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -73,7 +73,9 @@ /* use bmesh operator flags for a few operators */ #define BMO_ELE_TAG 1 -/* ****************************** MIRROR **************** */ +/* -------------------------------------------------------------------- */ +/** \name Select Mirror + * \{ */ void EDBM_select_mirrored( BMEditMesh *em, const int axis, const bool extend, @@ -166,21 +168,34 @@ void EDBM_select_mirrored( *r_totfail = totfail; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Auto-Merge + * + * Used after transform operations. + * \{ */ + void EDBM_automerge(Scene *scene, Object *obedit, bool update, const char hflag) { bool ok; BMEditMesh *em = BKE_editmesh_from_object(obedit); - ok = BMO_op_callf(em->bm, BMO_FLAG_DEFAULTS, - "automerge verts=%hv dist=%f", - hflag, scene->toolsettings->doublimit); + ok = BMO_op_callf( + em->bm, BMO_FLAG_DEFAULTS, + "automerge verts=%hv dist=%f", + hflag, scene->toolsettings->doublimit); if (LIKELY(ok) && update) { EDBM_update_generic(em, true, true); } } -/* ****************************** SELECTION ROUTINES **************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Back-Buffer OpenGL Selection + * \{ */ unsigned int bm_solidoffs = 0, bm_wireoffs = 0, bm_vertoffs = 0; /* set in drawobject.c ... for colorindices */ @@ -199,21 +214,21 @@ bool EDBM_backbuf_border_init(ViewContext *vc, short xmin, short ymin, short xma struct ImBuf *buf; unsigned int *dr; int a; - + if (vc->obedit == NULL || !V3D_IS_ZBUF(vc->v3d)) { return false; } - + buf = ED_view3d_backbuf_read(vc, xmin, ymin, xmax, ymax); if ((buf == NULL) || (bm_vertoffs == 0)) { return false; } dr = buf->rect; - + /* build selection lookup */ selbuf = edbm_backbuf_alloc(bm_vertoffs + 1); - + a = (xmax - xmin + 1) * (ymax - ymin + 1); while (a--) { if (*dr > 0 && *dr <= bm_vertoffs) { @@ -263,9 +278,9 @@ static void edbm_mask_lasso_px_cb(int x, int x_end, int y, void *user_data) /* mcords is a polygon mask * - grab backbuffer, - * - draw with black in backbuffer, + * - draw with black in backbuffer, * - grab again and compare - * returns 'OK' + * returns 'OK' */ bool EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax) { @@ -273,7 +288,7 @@ bool EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short struct ImBuf *buf; int a; struct LassoMaskData lasso_mask_data; - + /* method in use for face selecting too */ if (vc->obedit == NULL) { if (!BKE_paint_select_elem_test(vc->obact)) { @@ -302,7 +317,7 @@ bool EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short /* build selection lookup */ selbuf = edbm_backbuf_alloc(bm_vertoffs + 1); - + a = (xmax - xmin + 1) * (ymax - ymin + 1); while (a--) { if (*dr > 0 && *dr <= bm_vertoffs && *dr_mask == true) { @@ -323,7 +338,7 @@ bool EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads) unsigned int *dr; short xmin, ymin, xmax, ymax, xc, yc; int radsq; - + /* method in use for face selecting too */ if (vc->obedit == NULL) { if (!BKE_paint_select_elem_test(vc->obact)) { @@ -342,7 +357,7 @@ bool EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads) } dr = buf->rect; - + /* build selection lookup */ selbuf = edbm_backbuf_alloc(bm_vertoffs + 1); radsq = rads * rads; @@ -358,12 +373,12 @@ bool EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads) IMB_freeImBuf(buf); return true; - + } +/** \} */ /* -------------------------------------------------------------------- */ - /** \name Find Nearest Vert/Edge/Face * * \note Screen-space manhatten distances are used here, @@ -445,11 +460,14 @@ BMVert *EDBM_vert_find_nearest_ex( float dist_test; unsigned int index; BMVert *eve; - + + /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */ + ED_view3d_backbuf_validate(vc); + index = ED_view3d_backbuf_sample_rect( vc, vc->mval, dist_px, bm_wireoffs, 0xFFFFFF, &dist_test); eve = index ? BM_vert_at_index_find_or_table(bm, index - 1) : NULL; - + if (eve) { if (dist_test < *r_dist) { *r_dist = dist_test; @@ -630,9 +648,18 @@ BMEdge *EDBM_edge_find_nearest_ex( float dist_test = 0.0f; unsigned int index; BMEdge *eed; - + + /* Make sure that the edges are considered for selection. + * TODO: cleanup: add `selectmode` as a parameter */ + const short ts_selectmode = vc->scene->toolsettings->selectmode; + vc->scene->toolsettings->selectmode |= SCE_SELECT_EDGE; + + /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */ ED_view3d_backbuf_validate(vc); + /* restore `selectmode` */ + vc->scene->toolsettings->selectmode = ts_selectmode; + index = ED_view3d_backbuf_sample_rect(vc, vc->mval, dist_px, bm_solidoffs, bm_wireoffs, &dist_test); eed = index ? BM_edge_at_index_find_or_table(bm, index - 1) : NULL; @@ -799,7 +826,7 @@ BMFace *EDBM_face_find_nearest_ex( index = ED_view3d_backbuf_sample(vc, vc->mval[0], vc->mval[1]); efa = index ? BM_face_at_index_find_or_table(bm, index - 1) : NULL; - + if (r_efa_zbuf) { *r_efa_zbuf = efa; } @@ -877,8 +904,8 @@ BMFace *EDBM_face_find_nearest(ViewContext *vc, float *r_dist) #undef FIND_NEAR_CYCLE_THRESHOLD_MIN -/* best distance based on screen coords. - * use em->selectmode to define how to use +/* best distance based on screen coords. + * use em->selectmode to define how to use * selected vertices and edges get disadvantage * return 1 if found one */ @@ -894,7 +921,7 @@ static int unified_findnearest(ViewContext *vc, BMVert **r_eve, BMEdge **r_eed, float dist = dist_init; BMFace *efa_zbuf = NULL; BMEdge *eed_zbuf = NULL; - + BMVert *eve = NULL; BMEdge *eed = NULL; BMFace *efa = NULL; @@ -956,9 +983,11 @@ static int unified_findnearest(ViewContext *vc, BMVert **r_eve, BMEdge **r_eed, /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Select Similar (Vert/Edge/Face) Operator + * \{ */ -/* **************** SIMILAR "group" SELECTS. FACE, EDGE AND VERTEX ************** */ -static EnumPropertyItem prop_similar_compare_types[] = { +static const EnumPropertyItem prop_similar_compare_types[] = { {SIM_CMP_EQ, "EQUAL", 0, "Equal", ""}, {SIM_CMP_GT, "GREATER", 0, "Greater", ""}, {SIM_CMP_LT, "LESS", 0, "Less", ""}, @@ -966,7 +995,7 @@ static EnumPropertyItem prop_similar_compare_types[] = { {0, NULL, 0, NULL, NULL} }; -static EnumPropertyItem prop_similar_types[] = { +static const EnumPropertyItem prop_similar_types[] = { {SIMVERT_NORMAL, "NORMAL", 0, "Normal", ""}, {SIMVERT_FACE, "FACE", 0, "Amount of Adjacent Faces", ""}, {SIMVERT_VGROUP, "VGROUP", 0, "Vertex Groups", ""}, @@ -1034,7 +1063,7 @@ static int similar_face_select_exec(bContext *C, wmOperator *op) EDBM_update_generic(em, false, false); return OPERATOR_FINISHED; -} +} /* ***************************************************** */ @@ -1140,8 +1169,9 @@ static int edbm_select_similar_exec(bContext *C, wmOperator *op) else return similar_face_select_exec(C, op); } -static EnumPropertyItem *select_similar_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), - bool *r_free) +static const EnumPropertyItem *select_similar_type_itemf( + bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), + bool *r_free) { Object *obedit; @@ -1193,15 +1223,15 @@ void MESH_OT_select_similar(wmOperatorType *ot) ot->name = "Select Similar"; ot->idname = "MESH_OT_select_similar"; ot->description = "Select similar vertices, edges or faces by property types"; - + /* api callbacks */ ot->invoke = WM_menu_invoke; ot->exec = edbm_select_similar_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* properties */ prop = ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, SIMVERT_NORMAL, "Type", ""); RNA_def_enum_funcs(prop, select_similar_type_itemf); @@ -1211,9 +1241,11 @@ void MESH_OT_select_similar(wmOperatorType *ot) RNA_def_float(ot->srna, "threshold", 0.0f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f); } +/** \} */ /* -------------------------------------------------------------------- */ -/* Select Similar Regions */ +/** \name Select Similar Region Operator + * \{ */ static int edbm_select_similar_region_exec(bContext *C, wmOperator *op) { @@ -1234,9 +1266,10 @@ static int edbm_select_similar_region_exec(bContext *C, wmOperator *op) } groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__); - group_tot = BM_mesh_calc_face_groups(bm, groups_array, &group_index, - NULL, NULL, - BM_ELEM_SELECT, BM_VERT); + group_tot = BM_mesh_calc_face_groups( + bm, groups_array, &group_index, + NULL, NULL, + BM_ELEM_SELECT, BM_VERT); BM_mesh_elem_table_ensure(bm, BM_FACE); @@ -1277,7 +1310,7 @@ static int edbm_select_similar_region_exec(bContext *C, wmOperator *op) MEM_freeN(group_index); if (changed) { - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } else { BKE_report(op->reports, RPT_WARNING, "No matching face regions found"); @@ -1301,8 +1334,11 @@ void MESH_OT_select_similar_region(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ -/* **************** Mode Select *************** */ +/* -------------------------------------------------------------------- */ +/** \name Select Mode Vert/Edge/Face Operator + * \{ */ static int edbm_select_mode_exec(bContext *C, wmOperator *op) { @@ -1335,14 +1371,14 @@ void MESH_OT_select_mode(wmOperatorType *ot) { PropertyRNA *prop; - static EnumPropertyItem elem_items[] = { + static const EnumPropertyItem elem_items[] = { {SCE_SELECT_VERTEX, "VERT", ICON_VERTEXSEL, "Vertices", ""}, {SCE_SELECT_EDGE, "EDGE", ICON_EDGESEL, "Edges", ""}, {SCE_SELECT_FACE, "FACE", ICON_FACESEL, "Faces", ""}, {0, NULL, 0, NULL, NULL}, }; - static EnumPropertyItem actions_items[] = { + static const EnumPropertyItem actions_items[] = { {0, "DISABLE", 0, "Disable", "Disable selected markers"}, {1, "ENABLE", 0, "Enable", "Enable selected markers"}, {2, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"}, @@ -1373,12 +1409,15 @@ void MESH_OT_select_mode(wmOperatorType *ot) RNA_def_enum(ot->srna, "action", actions_items, 2, "Action", "Selection action to execute"); } -/* ***************************************************** */ +/** \} */ -/* **************** LOOP SELECTS *************** */ +/* -------------------------------------------------------------------- */ +/** \name Select Loop (Non Modal) Operator + * \{ */ -static void walker_select_count(BMEditMesh *em, int walkercode, void *start, const bool select, const bool select_mix, - int *r_totsel, int *r_totunsel) +static void walker_select_count( + BMEditMesh *em, int walkercode, void *start, const bool select, const bool select_mix, + int *r_totsel, int *r_totunsel) { BMesh *bm = em->bm; BMElem *ele; @@ -1433,7 +1472,7 @@ static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op) BMEdge **edarray; int edindex; const bool is_ring = RNA_boolean_get(op->ptr, "ring"); - + BMIter iter; int totedgesel = 0; @@ -1442,17 +1481,17 @@ static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op) totedgesel++; } } - + edarray = MEM_mallocN(sizeof(BMEdge *) * totedgesel, "edge array"); edindex = 0; - + BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { edarray[edindex] = eed; edindex++; } } - + if (is_ring) { for (edindex = 0; edindex < totedgesel; edindex += 1) { eed = edarray[edindex]; @@ -1469,8 +1508,8 @@ static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op) } MEM_freeN(edarray); // if (EM_texFaceCheck()) - - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit); + + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; } @@ -1481,23 +1520,23 @@ void MESH_OT_loop_multi_select(wmOperatorType *ot) ot->name = "Multi Select Loops"; ot->idname = "MESH_OT_loop_multi_select"; ot->description = "Select a loop of connected edges by connection type"; - + /* api callbacks */ ot->exec = edbm_loop_multiselect_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* properties */ RNA_def_boolean(ot->srna, "ring", 0, "Ring", ""); } - -/* ***************** MAIN MOUSE SELECTION ************** */ - +/** \} */ -/* ***************** loop select (non modal) ************** */ +/* -------------------------------------------------------------------- */ +/** \name Select Loop (Cursor Pick) Operator + * \{ */ static void mouse_mesh_loop_face(BMEditMesh *em, BMEdge *eed, bool select, bool select_clear) { @@ -1552,7 +1591,6 @@ static void mouse_mesh_loop_edge(BMEditMesh *em, BMEdge *eed, bool select, bool } } - static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle, bool ring) { ViewContext vc; @@ -1569,9 +1607,17 @@ static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool de mvalf[1] = (float)(vc.mval[1] = mval[1]); em = vc.em; + /* Make sure that the edges are also considered for selection. + * TODO: cleanup: add `selectmode` as a parameter */ + const short ts_selectmode = vc.scene->toolsettings->selectmode; + vc.scene->toolsettings->selectmode |= SCE_SELECT_EDGE; + /* no afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad */ ED_view3d_backbuf_validate(&vc); + /* restore `selectmode` */ + vc.scene->toolsettings->selectmode = ts_selectmode; + eed = EDBM_edge_find_nearest_ex(&vc, &dist, NULL, true, true, NULL); if (eed == NULL) { return false; @@ -1621,11 +1667,15 @@ static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool de /* We can't be sure this has already been set... */ ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); - if (ED_view3d_project_float_object(vc.ar, eed->v1->co, v1_co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) { + if (ED_view3d_project_float_object( + vc.ar, eed->v1->co, v1_co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) + { length_1 = len_squared_v2v2(mvalf, v1_co); } - if (ED_view3d_project_float_object(vc.ar, eed->v2->co, v2_co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) { + if (ED_view3d_project_float_object( + vc.ar, eed->v2->co, v2_co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) + { length_2 = len_squared_v2v2(mvalf, v2_co); } #if 0 @@ -1652,7 +1702,9 @@ static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool de float co[2], tdist; BM_face_calc_center_mean(f, cent); - if (ED_view3d_project_float_object(vc.ar, cent, co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) { + if (ED_view3d_project_float_object( + vc.ar, cent, co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) + { tdist = len_squared_v2v2(mvalf, co); if (tdist < best_dist) { /* printf("Best face: %p (%f)\n", f, tdist);*/ @@ -1669,21 +1721,22 @@ static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool de } } - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); return true; } static int edbm_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - + view3d_operator_needs_opengl(C); - - if (mouse_mesh_loop(C, event->mval, - RNA_boolean_get(op->ptr, "extend"), - RNA_boolean_get(op->ptr, "deselect"), - RNA_boolean_get(op->ptr, "toggle"), - RNA_boolean_get(op->ptr, "ring"))) + + if (mouse_mesh_loop( + C, event->mval, + RNA_boolean_get(op->ptr, "extend"), + RNA_boolean_get(op->ptr, "deselect"), + RNA_boolean_get(op->ptr, "toggle"), + RNA_boolean_get(op->ptr, "ring"))) { return OPERATOR_FINISHED; } @@ -1698,14 +1751,14 @@ void MESH_OT_loop_select(wmOperatorType *ot) ot->name = "Loop Select"; ot->idname = "MESH_OT_loop_select"; ot->description = "Select a loop of connected edges"; - + /* api callbacks */ ot->invoke = edbm_select_loop_invoke; ot->poll = ED_operator_editmesh_region_view3d; - + /* flags */ ot->flag = OPTYPE_UNDO; - + /* properties */ RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "Extend the selection"); RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Remove from the selection"); @@ -1719,11 +1772,11 @@ void MESH_OT_edgering_select(wmOperatorType *ot) ot->name = "Edge Ring Select"; ot->idname = "MESH_OT_edgering_select"; ot->description = "Select an edge ring"; - + /* callbacks */ ot->invoke = edbm_select_loop_invoke; ot->poll = ED_operator_editmesh_region_view3d; - + /* flags */ ot->flag = OPTYPE_UNDO; @@ -1733,7 +1786,12 @@ void MESH_OT_edgering_select(wmOperatorType *ot) RNA_def_boolean(ot->srna, "ring", 1, "Select Ring", "Select ring"); } -/* ******************** (de)select all operator **************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name (De)Select All Operator + * \{ */ + static int edbm_select_all_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -1756,7 +1814,7 @@ static int edbm_select_all_exec(bContext *C, wmOperator *op) break; } - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; } @@ -1778,13 +1836,19 @@ void MESH_OT_select_all(wmOperatorType *ot) WM_operator_properties_select_all(ot); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Interior Faces Operator + * \{ */ + static int edbm_faces_select_interior_exec(bContext *C, wmOperator *UNUSED(op)) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); if (EDBM_select_interior_faces(em)) { - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; } @@ -1809,10 +1873,15 @@ void MESH_OT_select_interior_faces(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Picking API + * + * Here actual select happens, + * Gets called via generic mouse select operator. + * \{ */ -/* ************************************************** */ -/* here actual select happens */ -/* gets called via generic mouse select operator */ bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle) { ViewContext vc; @@ -1921,13 +1990,19 @@ bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect } - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); return true; } return false; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Mode Utilities + * \{ */ + static void edbm_strip_selections(BMEditMesh *em) { BMEditSelection *ese, *nextese; @@ -1966,11 +2041,11 @@ void EDBM_selectmode_set(BMEditMesh *em) BMEdge *eed; BMFace *efa; BMIter iter; - + em->bm->selectmode = em->selectmode; 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) @@ -2133,8 +2208,9 @@ void EDBM_selectmode_convert(BMEditMesh *em, const short selectmode_old, const s } /* user facing function, does notification */ -bool EDBM_selectmode_toggle(bContext *C, const short selectmode_new, - const int action, const bool use_extend, const bool use_expand) +bool EDBM_selectmode_toggle( + bContext *C, const short selectmode_new, + const int action, const bool use_extend, const bool use_expand) { ToolSettings *ts = CTX_data_tool_settings(C); Object *obedit = CTX_data_edit_object(C); @@ -2230,9 +2306,10 @@ bool EDBM_selectmode_toggle(bContext *C, const short selectmode_new, * * \return true if the mode is changed. */ -bool EDBM_selectmode_disable(Scene *scene, BMEditMesh *em, - const short selectmode_disable, - const short selectmode_fallback) +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 */ @@ -2255,6 +2332,12 @@ bool EDBM_selectmode_disable(Scene *scene, BMEditMesh *em, } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Toggle + * \{ */ + void EDBM_deselect_by_material(BMEditMesh *em, const short index, const bool select) { BMIter iter; @@ -2283,7 +2366,7 @@ void EDBM_select_swap(BMEditMesh *em) /* exported for UV */ BMVert *eve; BMEdge *eed; BMFace *efa; - + if (em->bm->selectmode & SCE_SELECT_VERTEX) { BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) @@ -2306,9 +2389,17 @@ void EDBM_select_swap(BMEditMesh *em) /* exported for UV */ } } -// if (EM_texFaceCheck()) } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Interior Faces + * + * \note This algorithm is limited to single faces and could be improved, see: + * https://blender.stackexchange.com/questions/18916 + * \{ */ + bool EDBM_select_interior_faces(BMEditMesh *em) { BMesh *bm = em->bm; @@ -2341,8 +2432,13 @@ bool EDBM_select_interior_faces(BMEditMesh *em) return changed; } +/** \} */ -/************************ Select Linked Operator *************************/ +/* -------------------------------------------------------------------- */ +/** \name Select Linked Operator + * + * Support delimiting on different edge properties. + * \{ */ /* so we can have last-used default depend on selection mode (rare exception!) */ #define USE_LINKED_SELECT_DEFAULT_HACK @@ -2402,10 +2498,10 @@ static bool select_linked_delimit_test( * Gets the default from the operator fallback to own last-used value * (selected based on mode) */ -static int select_linked_delimit_default_from_op(wmOperator *op, BMEditMesh *em) +static int select_linked_delimit_default_from_op(wmOperator *op, int select_mode) { static char delimit_last_store[2] = {0, BMO_DELIM_SEAM}; - int delimit_last_index = (em->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0; + int delimit_last_index = (select_mode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0; char *delimit_last = &delimit_last_store[delimit_last_index]; PropertyRNA *prop_delimit = RNA_struct_find_property(op->ptr, "delimit"); int delimit; @@ -2475,7 +2571,7 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op) BMWalker walker; #ifdef USE_LINKED_SELECT_DEFAULT_HACK - int delimit = select_linked_delimit_default_from_op(op, em); + int delimit = select_linked_delimit_default_from_op(op, em->selectmode); #else int delimit = RNA_enum_get(op->ptr, "delimit"); #endif @@ -2633,7 +2729,7 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op) select_linked_delimit_end(em); } - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; } @@ -2645,7 +2741,7 @@ void MESH_OT_select_linked(wmOperatorType *ot) /* identifiers */ ot->name = "Select Linked All"; ot->idname = "MESH_OT_select_linked"; - ot->description = "Select all vertices linked to the active mesh"; + ot->description = "Select all vertices connected to the current selection"; /* api callbacks */ ot->exec = edbm_select_linked_exec; @@ -2663,6 +2759,12 @@ void MESH_OT_select_linked(wmOperatorType *ot) #endif } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Linked (Cursor Pick) Operator + * \{ */ + static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op); static void edbm_select_linked_pick_ex(BMEditMesh *em, BMElem *ele, bool sel, int delimit) @@ -2801,13 +2903,13 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE /* return warning! */ if (unified_findnearest(&vc, &eve, &eed, &efa) == 0) { - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_CANCELLED; } #ifdef USE_LINKED_SELECT_DEFAULT_HACK - int delimit = select_linked_delimit_default_from_op(op, em); + int delimit = select_linked_delimit_default_from_op(op, em->selectmode); #else int delimit = RNA_enum_get(op->ptr, "delimit"); #endif @@ -2822,7 +2924,7 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE RNA_int_set(op->ptr, "index", index); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; } @@ -2844,14 +2946,14 @@ static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op) BMElem *ele = EDBM_elem_from_index_any(em, index); #ifdef USE_LINKED_SELECT_DEFAULT_HACK - int delimit = select_linked_delimit_default_from_op(op, em); + int delimit = select_linked_delimit_default_from_op(op, em->selectmode); #else int delimit = RNA_enum_get(op->ptr, "delimit"); #endif edbm_select_linked_pick_ex(em, ele, sel, delimit); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; } @@ -2864,15 +2966,15 @@ void MESH_OT_select_linked_pick(wmOperatorType *ot) ot->name = "Select Linked"; ot->idname = "MESH_OT_select_linked_pick"; ot->description = "(De)select all vertices linked to the edge under the mouse cursor"; - + /* api callbacks */ ot->invoke = edbm_select_linked_pick_invoke; ot->exec = edbm_select_linked_pick_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", ""); prop = RNA_def_enum_flag(ot->srna, "delimit", rna_enum_mesh_delimit_mode_items, BMO_DELIM_SEAM, "Delimit", "Delimit selected region"); @@ -2885,6 +2987,11 @@ void MESH_OT_select_linked_pick(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Face by Sides Operator + * \{ */ static int edbm_select_face_by_sides_exec(bContext *C, wmOperator *op) { @@ -2960,6 +3067,11 @@ void MESH_OT_select_face_by_sides(wmOperatorType *ot) RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend the selection"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Loose Operator + * \{ */ static int edbm_select_loose_exec(bContext *C, wmOperator *op) { @@ -3031,6 +3143,11 @@ void MESH_OT_select_loose(wmOperatorType *ot) RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Mirror Operator + * \{ */ static int edbm_select_mirror_exec(bContext *C, wmOperator *op) { @@ -3079,7 +3196,11 @@ void MESH_OT_select_mirror(wmOperatorType *ot) RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the existing selection"); } -/* ******************** **************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select More Operator + * \{ */ static int edbm_select_more_exec(bContext *C, wmOperator *op) { @@ -3089,7 +3210,7 @@ static int edbm_select_more_exec(bContext *C, wmOperator *op) EDBM_select_more(em, use_face_step); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; } @@ -3103,13 +3224,19 @@ void MESH_OT_select_more(wmOperatorType *ot) /* api callbacks */ ot->exec = edbm_select_more_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; RNA_def_boolean(ot->srna, "use_face_step", true, "Face Step", "Connected faces (instead of edges)"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select More Operator + * \{ */ + static int edbm_select_less_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -3118,7 +3245,7 @@ static int edbm_select_less_exec(bContext *C, wmOperator *op) EDBM_select_less(em, use_face_step); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; } @@ -3132,13 +3259,19 @@ void MESH_OT_select_less(wmOperatorType *ot) /* api callbacks */ ot->exec = edbm_select_less_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; RNA_def_boolean(ot->srna, "use_face_step", true, "Face Step", "Connected faces (instead of edges)"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select N'th Operator + * \{ */ + /** * Check if we're connected to another selected efge. */ @@ -3361,13 +3494,18 @@ void MESH_OT_select_nth(wmOperatorType *ot) void em_setup_viewcontext(bContext *C, ViewContext *vc) { - view3d_set_viewcontext(C, vc); - + ED_view3d_viewcontext_init(C, vc); + if (vc->obedit) { vc->em = BKE_editmesh_from_object(vc->obedit); } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Sharp Edges Operator + * \{ */ static int edbm_select_sharp_edges_exec(bContext *C, wmOperator *op) { @@ -3395,6 +3533,13 @@ static int edbm_select_sharp_edges_exec(bContext *C, wmOperator *op) } } + if ((em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0) { + /* Since we can't select individual edges, select faces connected to them. */ + EDBM_selectmode_convert(em, SCE_SELECT_EDGE, SCE_SELECT_FACE); + } + else { + EDBM_selectmode_flush(em); + } WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; @@ -3408,20 +3553,26 @@ void MESH_OT_edges_select_sharp(wmOperatorType *ot) ot->name = "Select Sharp Edges"; ot->description = "Select all sharp-enough edges"; ot->idname = "MESH_OT_edges_select_sharp"; - + /* api callbacks */ ot->exec = edbm_select_sharp_edges_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* props */ prop = RNA_def_float_rotation(ot->srna, "sharpness", 0, NULL, DEG2RADF(0.01f), DEG2RADF(180.0f), "Sharpness", "", DEG2RADF(1.0f), DEG2RADF(180.0f)); RNA_def_property_float_default(prop, DEG2RADF(30.0f)); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Linked Flat Faces Operator + * \{ */ + static int edbm_select_linked_flat_faces_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -3489,20 +3640,26 @@ void MESH_OT_faces_select_linked_flat(wmOperatorType *ot) ot->name = "Select Linked Flat Faces"; ot->description = "Select linked faces by angle"; ot->idname = "MESH_OT_faces_select_linked_flat"; - + /* api callbacks */ ot->exec = edbm_select_linked_flat_faces_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* props */ prop = RNA_def_float_rotation(ot->srna, "sharpness", 0, NULL, DEG2RADF(0.01f), DEG2RADF(180.0f), "Sharpness", "", DEG2RADF(1.0f), DEG2RADF(180.0f)); RNA_def_property_float_default(prop, DEG2RADF(1.0f)); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Non-Manifold Operator + * \{ */ + static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -3524,12 +3681,12 @@ static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op) /* Selects isolated verts, and edges that do not have 2 neighboring * faces */ - + if (em->selectmode == SCE_SELECT_FACE) { BKE_report(op->reports, RPT_ERROR, "Does not work in face selection mode"); return OPERATOR_CANCELLED; } - + if (use_verts) { BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { @@ -3539,7 +3696,7 @@ static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op) } } } - + 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)) { @@ -3570,11 +3727,11 @@ void MESH_OT_select_non_manifold(wmOperatorType *ot) ot->name = "Select Non Manifold"; ot->description = "Select all non-manifold vertices or edges"; ot->idname = "MESH_OT_select_non_manifold"; - + /* api callbacks */ ot->exec = edbm_select_non_manifold_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -3594,6 +3751,12 @@ void MESH_OT_select_non_manifold(wmOperatorType *ot) "Vertices connecting multiple face regions"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Random Operator + * \{ */ + static int edbm_select_random_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -3640,9 +3803,9 @@ static int edbm_select_random_exec(bContext *C, wmOperator *op) else { EDBM_deselect_flush(em); } - + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - + return OPERATOR_FINISHED; } @@ -3659,11 +3822,17 @@ void MESH_OT_select_random(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* props */ WM_operator_properties_select_random(ot); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Ungrouped Operator + * \{ */ + static int edbm_select_ungrouped_poll(bContext *C) { if (ED_operator_editmesh(C)) { @@ -3730,6 +3899,11 @@ void MESH_OT_select_ungrouped(wmOperatorType *ot) RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Axis Operator + * \{ */ /* BMESH_TODO - some way to select on an arbitrary axis */ static int edbm_select_axis_exec(bContext *C, wmOperator *op) @@ -3784,14 +3958,14 @@ static int edbm_select_axis_exec(bContext *C, wmOperator *op) void MESH_OT_select_axis(wmOperatorType *ot) { - static EnumPropertyItem axis_mode_items[] = { + static const EnumPropertyItem axis_mode_items[] = { {0, "POSITIVE", 0, "Positive Axis", ""}, {1, "NEGATIVE", 0, "Negative Axis", ""}, {-1, "ALIGNED", 0, "Aligned Axis", ""}, {0, NULL, 0, NULL, NULL} }; - static EnumPropertyItem axis_items_xyz[] = { + static const EnumPropertyItem axis_items_xyz[] = { {0, "X_AXIS", 0, "X Axis", ""}, {1, "Y_AXIS", 0, "Y Axis", ""}, {2, "Z_AXIS", 0, "Z Axis", ""}, @@ -3816,6 +3990,12 @@ void MESH_OT_select_axis(wmOperatorType *ot) RNA_def_float(ot->srna, "threshold", 0.0001f, 0.000001f, 50.0f, "Threshold", "", 0.00001f, 10.0f); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Region to Loop Operator + * \{ */ + static int edbm_region_to_loop_exec(bContext *C, wmOperator *UNUSED(op)) { Object *obedit = CTX_data_edit_object(C); @@ -3829,22 +4009,22 @@ static int edbm_region_to_loop_exec(bContext *C, wmOperator *UNUSED(op)) BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { BMLoop *l1, *l2; BMIter liter1, liter2; - + BM_ITER_ELEM (l1, &liter1, f, BM_LOOPS_OF_FACE) { int tot = 0, totsel = 0; - + BM_ITER_ELEM (l2, &liter2, l1->e, BM_LOOPS_OF_EDGE) { tot++; totsel += BM_elem_flag_test(l2->f, BM_ELEM_SELECT) != 0; } - + if ((tot != totsel && totsel > 0) || (totsel == 1 && tot == 1)) BM_elem_flag_enable(l1->e, BM_ELEM_TAG); } } EDBM_flag_disable_all(em, BM_ELEM_SELECT); - + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { if (BM_elem_flag_test(e, BM_ELEM_TAG)) { BM_edge_select_set(em->bm, e, true); @@ -3879,29 +4059,36 @@ void MESH_OT_region_to_loop(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -static int loop_find_region(BMLoop *l, int flag, - GSet *visit_face_set, BMFace ***region_out) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Loop to Region Operator + * \{ */ + +static int loop_find_region( + BMLoop *l, int flag, + GSet *visit_face_set, BMFace ***region_out) { BMFace **region = NULL; BMFace **stack = NULL; BLI_array_declare(region); BLI_array_declare(stack); BMFace *f; - + BLI_array_append(stack, l->f); BLI_gset_insert(visit_face_set, l->f); - - while (BLI_array_count(stack) > 0) { + + while (BLI_array_len(stack) > 0) { BMIter liter1, liter2; BMLoop *l1, *l2; - + f = BLI_array_pop(stack); BLI_array_append(region, f); - + BM_ITER_ELEM (l1, &liter1, f, BM_LOOPS_OF_FACE) { if (BM_elem_flag_test(l1->e, flag)) continue; - + BM_ITER_ELEM (l2, &liter2, l1->e, BM_LOOPS_OF_EDGE) { /* avoids finding same region twice * (otherwise) the logic works fine without */ @@ -3915,11 +4102,11 @@ static int loop_find_region(BMLoop *l, int flag, } } } - + BLI_array_free(stack); - + *region_out = region; - return BLI_array_count(region); + return BLI_array_len(region); } static int verg_radial(const void *va, const void *vb) @@ -3927,10 +4114,9 @@ static int verg_radial(const void *va, const void *vb) const BMEdge *e_a = *((const BMEdge **)va); const BMEdge *e_b = *((const BMEdge **)vb); - int a, b; - a = BM_edge_face_count(e_a); - b = BM_edge_face_count(e_b); - + const int a = BM_edge_face_count(e_a); + const int b = BM_edge_face_count(e_b); + if (a > b) return -1; if (a < b) return 1; return 0; @@ -3949,7 +4135,7 @@ static int loop_find_regions(BMEditMesh *em, const bool selbigger) const int edges_len = em->bm->totedgesel; BMEdge *e, **edges; int count = 0, i; - + visit_face_set = BLI_gset_ptr_new_ex(__func__, edges_len); edges = MEM_mallocN(sizeof(*edges) * edges_len, __func__); @@ -3963,21 +4149,21 @@ static int loop_find_regions(BMEditMesh *em, const bool selbigger) BM_elem_flag_disable(e, BM_ELEM_TAG); } } - + /* sort edges by radial cycle length */ qsort(edges, edges_len, sizeof(*edges), verg_radial); - + for (i = 0; i < edges_len; i++) { BMIter liter; BMLoop *l; BMFace **region = NULL, **region_out; int c, tot = 0; - + e = edges[i]; - + if (!BM_elem_flag_test(e, BM_ELEM_TAG)) continue; - + BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) { if (BLI_gset_haskey(visit_face_set, l->f)) continue; @@ -3999,26 +4185,26 @@ static int loop_find_regions(BMEditMesh *em, const bool selbigger) MEM_freeN(region_out); } } - + if (region) { int j; - + for (j = 0; j < tot; j++) { BM_elem_flag_enable(region[j], BM_ELEM_TAG); BM_ITER_ELEM (l, &liter, region[j], BM_LOOPS_OF_FACE) { BM_elem_flag_disable(l->e, BM_ELEM_TAG); } } - + count += tot; - + MEM_freeN(region); } } - + MEM_freeN(edges); BLI_gset_free(visit_face_set, NULL); - + return count; } @@ -4029,25 +4215,23 @@ static int edbm_loop_to_region_exec(bContext *C, wmOperator *op) BMIter iter; BMFace *f; const bool select_bigger = RNA_boolean_get(op->ptr, "select_bigger"); - int a, b; - /* find the set of regions with smallest number of total faces */ BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); - a = loop_find_regions(em, select_bigger); - b = loop_find_regions(em, !select_bigger); + const int a = loop_find_regions(em, select_bigger); + const int b = loop_find_regions(em, !select_bigger); BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); loop_find_regions(em, ((a <= b) != select_bigger) ? select_bigger : !select_bigger); - + EDBM_flag_disable_all(em, BM_ELEM_SELECT); - + BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { if (BM_elem_flag_test(f, BM_ELEM_TAG) && !BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { BM_face_select_set(em->bm, f, true); } } - + EDBM_selectmode_flush(em); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); @@ -4067,9 +4251,8 @@ void MESH_OT_loop_to_region(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + RNA_def_boolean(ot->srna, "select_bigger", 0, "Select Bigger", "Select bigger regions instead of smaller ones"); } - -/************************ Select Path Operator *************************/ +/** \} */ |