diff options
Diffstat (limited to 'source/blender/editors/mesh/editmesh_select.c')
-rw-r--r-- | source/blender/editors/mesh/editmesh_select.c | 1490 |
1 files changed, 942 insertions, 548 deletions
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 019aa6d4201..634c65485e9 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -45,6 +45,7 @@ #include "BKE_report.h" #include "BKE_paint.h" #include "BKE_editmesh.h" +#include "BKE_layer.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" @@ -68,6 +69,9 @@ #include "bmesh_tools.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + #include "mesh_intern.h" /* own include */ /* use bmesh operator flags for a few operators */ @@ -209,7 +213,9 @@ static BLI_bitmap *edbm_backbuf_alloc(const int size) /* reads rect, and builds selection array for quick lookup */ /* returns if all is OK */ -bool EDBM_backbuf_border_init(ViewContext *vc, short xmin, short ymin, short xmax, short ymax) +bool EDBM_backbuf_border_init( + ViewContext *vc, short xmin, + short ymin, short xmax, short ymax) { struct ImBuf *buf; unsigned int *dr; @@ -332,7 +338,9 @@ bool EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short } /* circle shaped sample area */ -bool EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads) +bool EDBM_backbuf_circle_init( + ViewContext *vc, + short xs, short ys, short rads) { struct ImBuf *buf; unsigned int *dr; @@ -389,6 +397,18 @@ bool EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads) * to avoid the bias interfering with distance comparisons when mixing types. * \{ */ +#define FAKE_SELECT_MODE_BEGIN(vc, fake_select_mode, select_mode, select_mode_required) \ + short select_mode = select_mode_required; \ + bool fake_select_mode = (select_mode & (vc)->scene->toolsettings->selectmode) == 0; \ + if (fake_select_mode) { \ + (vc)->v3d->flag |= V3D_INVALID_BACKBUF; \ + } ((void)0) + +#define FAKE_SELECT_MODE_END(vc, fake_select_mode) \ + if (fake_select_mode) { \ + (vc)->v3d->flag |= V3D_INVALID_BACKBUF; \ + } ((void)0) + #define FIND_NEAR_SELECT_BIAS 5 #define FIND_NEAR_CYCLE_THRESHOLD_MIN 3 @@ -462,11 +482,16 @@ BMVert *EDBM_vert_find_nearest_ex( BMVert *eve; /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */ - ED_view3d_backbuf_validate(vc); + { + FAKE_SELECT_MODE_BEGIN(vc, fake_select_mode, select_mode, SCE_SELECT_VERTEX); + ED_view3d_backbuf_validate_with_select_mode(vc, select_mode); - 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; + 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; + + FAKE_SELECT_MODE_END(vc, fake_select_mode); + } if (eve) { if (dist_test < *r_dist) { @@ -649,19 +674,16 @@ BMEdge *EDBM_edge_find_nearest_ex( 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); + { + FAKE_SELECT_MODE_BEGIN(vc, fake_select_mode, select_mode, SCE_SELECT_EDGE); + ED_view3d_backbuf_validate_with_select_mode(vc, select_mode); - /* 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; - 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; + FAKE_SELECT_MODE_END(vc, fake_select_mode); + } if (r_eed_zbuf) { *r_eed_zbuf = eed; @@ -822,10 +844,15 @@ BMFace *EDBM_face_find_nearest_ex( unsigned int index; BMFace *efa; - ED_view3d_backbuf_validate(vc); + { + FAKE_SELECT_MODE_BEGIN(vc, fake_select_mode, select_mode, SCE_SELECT_FACE); + ED_view3d_backbuf_validate_with_select_mode(vc, select_mode); + + 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; - 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; + FAKE_SELECT_MODE_END(vc, fake_select_mode); + } if (r_efa_zbuf) { *r_efa_zbuf = efa; @@ -909,7 +936,9 @@ BMFace *EDBM_face_find_nearest(ViewContext *vc, float *r_dist) * selected vertices and edges get disadvantage * return 1 if found one */ -static int unified_findnearest(ViewContext *vc, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa) +static bool unified_findnearest( + ViewContext *vc, + Base **r_base, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa) { BMEditMesh *em = vc->em; static short mval_prev[2] = {-1, -1}; @@ -919,68 +948,143 @@ static int unified_findnearest(ViewContext *vc, BMVert **r_eve, BMEdge **r_eed, /* since edges select lines, we give dots advantage of ~20 pix */ const float dist_margin = (dist_init / 2); float dist = dist_init; - BMFace *efa_zbuf = NULL; - BMEdge *eed_zbuf = NULL; - - BMVert *eve = NULL; - BMEdge *eed = NULL; - BMFace *efa = NULL; + struct { + struct { + BMVert *ele; + Base *base; + } v; + struct { + BMEdge *ele; + Base *base; + } e, e_zbuf; + struct { + BMFace *ele; + Base *base; + } f, f_zbuf; + } hit = {{NULL}}; + + /* TODO(campbell): perform selection as one pass + * instead of many smaller passes (which doesn't work for zbuf occlusion). */ + uint bases_len = 0; + Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc->view_layer, &bases_len); /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */ - ED_view3d_backbuf_validate(vc); if ((dist > 0.0f) && em->selectmode & SCE_SELECT_FACE) { float dist_center = 0.0f; float *dist_center_p = (em->selectmode & (SCE_SELECT_EDGE | SCE_SELECT_VERTEX)) ? &dist_center : NULL; - efa = EDBM_face_find_nearest_ex(vc, &dist, dist_center_p, true, use_cycle, &efa_zbuf); - if (efa && dist_center_p) { - dist = min_ff(dist_margin, dist_center); - } + + for (uint base_index = 0; base_index < bases_len; base_index++) { + Base *base_iter = bases[base_index]; + Object *obedit = base_iter->object; + ED_view3d_viewcontext_init_object(vc, obedit); + ED_view3d_backbuf_validate(vc); + BMFace *efa_zbuf = NULL; + BMFace *efa_test = EDBM_face_find_nearest_ex(vc, &dist, dist_center_p, true, use_cycle, &efa_zbuf); + if (hit.f.ele && dist_center_p) { + dist = min_ff(dist_margin, dist_center); + } + if (efa_test) { + hit.f.base = base_iter; + hit.f.ele = efa_test; + } + if (efa_zbuf) { + hit.f_zbuf.base = base_iter; + hit.f_zbuf.ele = efa_zbuf; + } + } /* bases */ } if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_EDGE)) { float dist_center = 0.0f; float *dist_center_p = (em->selectmode & SCE_SELECT_VERTEX) ? &dist_center : NULL; - eed = EDBM_edge_find_nearest_ex(vc, &dist, dist_center_p, true, use_cycle, &eed_zbuf); - if (eed && dist_center_p) { - dist = min_ff(dist_margin, dist_center); - } + + for (uint base_index = 0; base_index < bases_len; base_index++) { + Base *base_iter = bases[base_index]; + Object *obedit = base_iter->object; + ED_view3d_viewcontext_init_object(vc, obedit); + ED_view3d_backbuf_validate(vc); + BMEdge *eed_zbuf = NULL; + BMEdge *eed_test = EDBM_edge_find_nearest_ex(vc, &dist, dist_center_p, true, use_cycle, &eed_zbuf); + if (hit.e.ele && dist_center_p) { + dist = min_ff(dist_margin, dist_center); + } + if (eed_test) { + hit.e.base = base_iter; + hit.e.ele = eed_test; + } + if (eed_zbuf) { + hit.e_zbuf.base = base_iter; + hit.e_zbuf.ele = eed_zbuf; + } + } /* bases */ } if ((dist > 0.0f) && em->selectmode & SCE_SELECT_VERTEX) { - eve = EDBM_vert_find_nearest_ex(vc, &dist, true, use_cycle); + for (uint base_index = 0; base_index < bases_len; base_index++) { + Base *base_iter = bases[base_index]; + Object *obedit = base_iter->object; + ED_view3d_viewcontext_init_object(vc, obedit); + ED_view3d_backbuf_validate(vc); + BMVert *eve_test = EDBM_vert_find_nearest_ex(vc, &dist, true, use_cycle); + if (eve_test) { + hit.v.base = base_iter; + hit.v.ele = eve_test; + } + } /* bases */ } + MEM_SAFE_FREE(bases); + /* return only one of 3 pointers, for frontbuffer redraws */ - if (eve) { - efa = NULL; eed = NULL; + if (hit.v.ele) { + hit.f.ele = NULL; + hit.e.ele = NULL; } - else if (eed) { - efa = NULL; + else if (hit.e.ele) { + hit.f.ele = NULL; } /* there may be a face under the cursor, who's center if too far away * use this if all else fails, it makes sense to select this */ - if ((eve || eed || efa) == 0) { - if (eed_zbuf) { - eed = eed_zbuf; + if ((hit.v.ele || hit.e.ele || hit.f.ele) == 0) { + if (hit.e_zbuf.ele) { + hit.e.base = hit.e_zbuf.base; + hit.e.ele = hit.e_zbuf.ele; } - else if (efa_zbuf) { - efa = efa_zbuf; + else if (hit.f_zbuf.ele) { + hit.f.base = hit.f_zbuf.base; + hit.f.ele = hit.f_zbuf.ele; } } mval_prev[0] = vc->mval[0]; mval_prev[1] = vc->mval[1]; - *r_eve = eve; - *r_eed = eed; - *r_efa = efa; + /* Only one element type will be non-null. */ + BLI_assert(((hit.v.ele != NULL) + (hit.e.ele != NULL) + (hit.f.ele != NULL)) <= 1); + + if (hit.v.ele) { + *r_base = hit.v.base; + } + if (hit.e.ele) { + *r_base = hit.e.base; + } + if (hit.f.ele) { + *r_base = hit.f.base; + } - return (eve || eed || efa); + *r_eve = hit.v.ele; + *r_eed = hit.e.ele; + *r_efa = hit.f.ele; + + return (hit.v.ele || hit.e.ele || hit.f.ele); } +#undef FAKE_SELECT_MODE_BEGIN +#undef FAKE_SELECT_MODE_END + /** \} */ /* -------------------------------------------------------------------- */ @@ -1014,13 +1118,13 @@ static const EnumPropertyItem prop_similar_types[] = { #endif {SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""}, - {SIMFACE_IMAGE, "IMAGE", 0, "Image", ""}, {SIMFACE_AREA, "AREA", 0, "Area", ""}, {SIMFACE_SIDES, "SIDES", 0, "Polygon Sides", ""}, {SIMFACE_PERIMETER, "PERIMETER", 0, "Perimeter", ""}, {SIMFACE_NORMAL, "NORMAL", 0, "Normal", ""}, {SIMFACE_COPLANAR, "COPLANAR", 0, "Co-planar", ""}, {SIMFACE_SMOOTH, "SMOOTH", 0, "Flat/Smooth", ""}, + {SIMFACE_FACEMAP, "FACE_MAP", 0, "Face-Map", ""}, #ifdef WITH_FREESTYLE {SIMFACE_FREESTYLE, "FREESTYLE_FACE", 0, "Freestyle Face Marks", ""}, #endif @@ -1199,7 +1303,7 @@ static const EnumPropertyItem *select_similar_type_itemf( #ifdef WITH_FREESTYLE const int a_end = SIMFACE_FREESTYLE; #else - const int a_end = SIMFACE_SMOOTH; + const int a_end = SIMFACE_FACEMAP; #endif for (a = SIMFACE_MATERIAL; a <= a_end; a++) { RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a); @@ -1466,50 +1570,60 @@ static void walker_select(BMEditMesh *em, int walkercode, void *start, const boo static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMEdge *eed; - BMEdge **edarray; - int edindex; const bool is_ring = RNA_boolean_get(op->ptr, "ring"); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMIter iter; - int totedgesel = 0; + if (em->bm->totedgesel == 0) { + continue; + } - BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { - totedgesel++; + BMEdge *eed; + BMEdge **edarray; + int edindex; + BMIter iter; + int totedgesel = 0; + + BM_ITER_MESH(eed, &iter, em->bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { + totedgesel++; + } } - } - edarray = MEM_mallocN(sizeof(BMEdge *) * totedgesel, "edge array"); - edindex = 0; + 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++; + 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]; - walker_select(em, BMW_EDGERING, eed, true); + if (is_ring) { + for (edindex = 0; edindex < totedgesel; edindex += 1) { + eed = edarray[edindex]; + walker_select(em, BMW_EDGERING, eed, true); + } + EDBM_selectmode_flush(em); } - EDBM_selectmode_flush(em); - } - else { - for (edindex = 0; edindex < totedgesel; edindex += 1) { - eed = edarray[edindex]; - walker_select(em, BMW_EDGELOOP, eed, true); + else { + for (edindex = 0; edindex < totedgesel; edindex += 1) { + eed = edarray[edindex]; + walker_select(em, BMW_EDGELOOP, eed, true); + } + EDBM_selectmode_flush(em); } - EDBM_selectmode_flush(em); - } - MEM_freeN(edarray); -// if (EM_texFaceCheck()) + MEM_freeN(edarray); + // if (EM_texFaceCheck()) - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -1607,17 +1721,6 @@ 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; @@ -1794,27 +1897,43 @@ void MESH_OT_edgering_select(wmOperatorType *ot) static int edbm_select_all_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - const int action = RNA_enum_get(op->ptr, "action"); + ViewLayer *view_layer = CTX_data_view_layer(C); + int action = RNA_enum_get(op->ptr, "action"); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + + if (action == SEL_TOGGLE) { + action = SEL_SELECT; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + if (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel) { + action = SEL_DESELECT; + break; + } + } + } - switch (action) { - case SEL_TOGGLE: - EDBM_select_toggle_all(em); - break; - case SEL_SELECT: - EDBM_flag_enable_all(em, BM_ELEM_SELECT); - break; - case SEL_DESELECT: - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - break; - case SEL_INVERT: - EDBM_select_swap(em); - EDBM_selectmode_flush(em); - break; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + switch (action) { + case SEL_SELECT: + EDBM_flag_enable_all(em, BM_ELEM_SELECT); + break; + case SEL_DESELECT: + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + break; + case SEL_INVERT: + EDBM_select_swap(em); + EDBM_selectmode_flush(em); + break; + } + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -1844,18 +1963,23 @@ void MESH_OT_select_all(wmOperatorType *ot) 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); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); - if (EDBM_select_interior_faces(em)) { - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; + if (!EDBM_select_interior_faces(em)) { + continue; + } + + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } + MEM_freeN(objects); + return OPERATOR_FINISHED; } void MESH_OT_select_interior_faces(wmOperatorType *ot) @@ -1885,6 +2009,8 @@ void MESH_OT_select_interior_faces(wmOperatorType *ot) bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle) { ViewContext vc; + + Base *basact = NULL; BMVert *eve = NULL; BMEdge *eed = NULL; BMFace *efa = NULL; @@ -1894,11 +2020,23 @@ bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect vc.mval[0] = mval[0]; vc.mval[1] = mval[1]; - if (unified_findnearest(&vc, &eve, &eed, &efa)) { + if (unified_findnearest(&vc, &basact, &eve, &eed, &efa)) { + ED_view3d_viewcontext_init_object(&vc, basact->object); /* Deselect everything */ - if (extend == false && deselect == false && toggle == false) - EDBM_flag_disable_all(vc.em, BM_ELEM_SELECT); + if (extend == false && deselect == false && toggle == false) { + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(vc.view_layer, &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob_iter = objects[ob_index]; + EDBM_flag_disable_all(BKE_editmesh_from_object(ob_iter), BM_ELEM_SELECT); + if (basact->object != ob_iter) { + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data); + } + } + MEM_freeN(objects); + } if (efa) { if (extend) { @@ -1981,16 +2119,41 @@ bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect EDBM_selectmode_flush(vc.em); - /* change active material on object */ - if (efa && efa->mat_nr != vc.obedit->actcol - 1) { - vc.obedit->actcol = efa->mat_nr + 1; - vc.em->mat_nr = efa->mat_nr; + if (efa) { + /* Change active material on object. */ + if (efa->mat_nr != vc.obedit->actcol - 1) { + vc.obedit->actcol = efa->mat_nr + 1; + vc.em->mat_nr = efa->mat_nr; + WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, NULL); + } - WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, NULL); + /* Change active face-map on object. */ + if (!BLI_listbase_is_empty(&vc.obedit->fmaps)) { + const int cd_fmap_offset = CustomData_get_offset(&vc.em->bm->pdata, CD_FACEMAP); + if (cd_fmap_offset != -1) { + int map = *((int *)BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset)); + if ((map < -1) || (map > BLI_listbase_count_at_most(&vc.obedit->fmaps, map))) { + map = -1; + } + map += 1; + if (map != vc.obedit->actfmap) { + /* We may want to add notifiers later, + * currently select update handles redraw. */ + vc.obedit->actfmap = map; + } + } + } } + /* Changing active object is handy since it allows us to + * switch UV layers, vgroups for eg. */ + if (vc.view_layer->basact != basact) { + vc.view_layer->basact = basact; + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, vc.scene); + } WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); + return true; } @@ -2212,6 +2375,8 @@ bool EDBM_selectmode_toggle( bContext *C, const short selectmode_new, const int action, const bool use_extend, const bool use_expand) { + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); ToolSettings *ts = CTX_data_tool_settings(C); Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = NULL; @@ -2225,6 +2390,7 @@ bool EDBM_selectmode_toggle( return ret; } + bool only_update = false; switch (action) { case -1: /* already set */ @@ -2232,21 +2398,24 @@ bool EDBM_selectmode_toggle( case 0: /* disable */ /* check we have something to do */ if ((em->selectmode & selectmode_new) == 0) { - return false; + only_update = true; + break; } em->selectmode &= ~selectmode_new; break; case 1: /* enable */ /* check we have something to do */ if ((em->selectmode & selectmode_new) != 0) { - return false; + only_update = true; + break; } em->selectmode |= selectmode_new; break; case 2: /* toggle */ /* can't disable this flag if its the only one set */ if (em->selectmode == selectmode_new) { - return false; + only_update = true; + break; } em->selectmode ^= selectmode_new; break; @@ -2255,10 +2424,30 @@ bool EDBM_selectmode_toggle( break; } + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob_iter = objects[ob_index]; + BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter); + if (em_iter != em) { + em_iter->selectmode = em->selectmode; + } + } + + if (only_update) { + MEM_freeN(objects); + return false; + } + if (use_extend == 0 || em->selectmode == 0) { if (use_expand) { const short selmode_max = highest_order_bit_s(ts->selectmode); - EDBM_selectmode_convert(em, selmode_max, selectmode_new); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob_iter = objects[ob_index]; + BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter); + EDBM_selectmode_convert(em_iter, selmode_max, selectmode_new); + } } } @@ -2267,24 +2456,18 @@ bool EDBM_selectmode_toggle( if (use_extend == 0 || em->selectmode == 0) { em->selectmode = SCE_SELECT_VERTEX; } - ts->selectmode = em->selectmode; - EDBM_selectmode_set(em); ret = true; break; case SCE_SELECT_EDGE: if (use_extend == 0 || em->selectmode == 0) { em->selectmode = SCE_SELECT_EDGE; } - ts->selectmode = em->selectmode; - EDBM_selectmode_set(em); ret = true; break; case SCE_SELECT_FACE: if (use_extend == 0 || em->selectmode == 0) { em->selectmode = SCE_SELECT_FACE; } - ts->selectmode = em->selectmode; - EDBM_selectmode_set(em); ret = true; break; default: @@ -2293,10 +2476,20 @@ bool EDBM_selectmode_toggle( } if (ret == true) { - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + ts->selectmode = em->selectmode; + em = NULL; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob_iter = objects[ob_index]; + BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter); + EDBM_selectmode_set(em_iter); + DEG_id_tag_update(ob_iter->data, DEG_TAG_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data); + } WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL); + DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE); } + MEM_freeN(objects); return ret; } @@ -2498,7 +2691,7 @@ 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, int select_mode) +static int select_linked_delimit_default_from_op(wmOperator *op, const int select_mode) { static char delimit_last_store[2] = {0, BMO_DELIM_SEAM}; int delimit_last_index = (select_mode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0; @@ -2564,172 +2757,186 @@ static void select_linked_delimit_end(BMEditMesh *em) static int edbm_select_linked_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - BMIter iter; - BMWalker walker; + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); #ifdef USE_LINKED_SELECT_DEFAULT_HACK - int delimit = select_linked_delimit_default_from_op(op, em->selectmode); + const int delimit_init = select_linked_delimit_default_from_op(op, scene->toolsettings->selectmode); #else - int delimit = RNA_enum_get(op->ptr, "delimit"); + const int delimit_init = RNA_enum_get(op->ptr, "delimit"); #endif - select_linked_delimit_validate(bm, &delimit); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); - if (delimit) { - select_linked_delimit_begin(em->bm, delimit); - } + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; - if (em->selectmode & SCE_SELECT_VERTEX) { - BMVert *v; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMIter iter; + BMWalker walker; - BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { - BM_elem_flag_set(v, BM_ELEM_TAG, BM_elem_flag_test(v, BM_ELEM_SELECT)); - } + int delimit = delimit_init; + + select_linked_delimit_validate(bm, &delimit); - /* exclude all delimited verts */ if (delimit) { - BMEdge *e; - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - if (!BMO_edge_flag_test(bm, e, BMO_ELE_TAG)) { - BM_elem_flag_disable(e->v1, BM_ELEM_TAG); - BM_elem_flag_disable(e->v2, BM_ELEM_TAG); - } - } + select_linked_delimit_begin(em->bm, delimit); } - BMW_init(&walker, em->bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL, - BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP, - BMW_FLAG_TEST_HIDDEN, - BMW_NIL_LAY); + if (em->selectmode & SCE_SELECT_VERTEX) { + BMVert *v; - if (delimit) { BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_TAG)) { - BMElem *ele_walk; - BMW_ITER (ele_walk, &walker, v) { - if (ele_walk->head.htype == BM_LOOP) { - BMVert *v_step = ((BMLoop *)ele_walk)->v; - BM_vert_select_set(em->bm, v_step, true); - BM_elem_flag_disable(v_step, BM_ELEM_TAG); - } - else { - BMEdge *e_step = (BMEdge *)ele_walk; - BLI_assert(ele_walk->head.htype == BM_EDGE); - BM_edge_select_set(em->bm, e_step, true); - BM_elem_flag_disable(e_step->v1, BM_ELEM_TAG); - BM_elem_flag_disable(e_step->v2, BM_ELEM_TAG); + BM_elem_flag_set(v, BM_ELEM_TAG, BM_elem_flag_test(v, BM_ELEM_SELECT)); + } + + /* exclude all delimited verts */ + if (delimit) { + BMEdge *e; + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + if (!BMO_edge_flag_test(bm, e, BMO_ELE_TAG)) { + BM_elem_flag_disable(e->v1, BM_ELEM_TAG); + BM_elem_flag_disable(e->v2, BM_ELEM_TAG); + } + } + } + + BMW_init(&walker, em->bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL, + BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP, + BMW_FLAG_TEST_HIDDEN, + BMW_NIL_LAY); + + if (delimit) { + BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + BMElem *ele_walk; + BMW_ITER (ele_walk, &walker, v) { + if (ele_walk->head.htype == BM_LOOP) { + BMVert *v_step = ((BMLoop *)ele_walk)->v; + BM_vert_select_set(em->bm, v_step, true); + BM_elem_flag_disable(v_step, BM_ELEM_TAG); + } + else { + BMEdge *e_step = (BMEdge *)ele_walk; + BLI_assert(ele_walk->head.htype == BM_EDGE); + BM_edge_select_set(em->bm, e_step, true); + BM_elem_flag_disable(e_step->v1, BM_ELEM_TAG); + BM_elem_flag_disable(e_step->v2, BM_ELEM_TAG); + } } } } } - } - else { - BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_TAG)) { - BMEdge *e_walk; - BMW_ITER (e_walk, &walker, v) { - BM_edge_select_set(em->bm, e_walk, true); - BM_elem_flag_disable(e_walk, BM_ELEM_TAG); + else { + BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + BMEdge *e_walk; + BMW_ITER (e_walk, &walker, v) { + BM_edge_select_set(em->bm, e_walk, true); + BM_elem_flag_disable(e_walk, BM_ELEM_TAG); + } } } } - } - BMW_end(&walker); + BMW_end(&walker); - EDBM_selectmode_flush(em); - } - else if (em->selectmode & SCE_SELECT_EDGE) { - BMEdge *e; + EDBM_selectmode_flush(em); + } + else if (em->selectmode & SCE_SELECT_EDGE) { + BMEdge *e; - if (delimit) { - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - BM_elem_flag_set( - e, BM_ELEM_TAG, - (BM_elem_flag_test(e, BM_ELEM_SELECT) && BMO_edge_flag_test(bm, e, BMO_ELE_TAG))); + if (delimit) { + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + BM_elem_flag_set( + e, BM_ELEM_TAG, + (BM_elem_flag_test(e, BM_ELEM_SELECT) && BMO_edge_flag_test(bm, e, BMO_ELE_TAG))); + } } - } - else { - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT)); + else { + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT)); + } } - } - - BMW_init(&walker, em->bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL, - BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP, - BMW_FLAG_TEST_HIDDEN, - BMW_NIL_LAY); - if (delimit) { - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_TAG)) { - BMElem *ele_walk; - BMW_ITER (ele_walk, &walker, e) { - if (ele_walk->head.htype == BM_LOOP) { - BMLoop *l_step = (BMLoop *)ele_walk; - BM_edge_select_set(em->bm, l_step->e, true); - BM_edge_select_set(em->bm, l_step->prev->e, true); - BM_elem_flag_disable(l_step->e, BM_ELEM_TAG); - } - else { - BMEdge *e_step = (BMEdge *)ele_walk; - BLI_assert(ele_walk->head.htype == BM_EDGE); - BM_edge_select_set(em->bm, e_step, true); - BM_elem_flag_disable(e_step, BM_ELEM_TAG); + BMW_init(&walker, em->bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL, + BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP, + BMW_FLAG_TEST_HIDDEN, + BMW_NIL_LAY); + + if (delimit) { + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + BMElem *ele_walk; + BMW_ITER (ele_walk, &walker, e) { + if (ele_walk->head.htype == BM_LOOP) { + BMLoop *l_step = (BMLoop *)ele_walk; + BM_edge_select_set(em->bm, l_step->e, true); + BM_edge_select_set(em->bm, l_step->prev->e, true); + BM_elem_flag_disable(l_step->e, BM_ELEM_TAG); + } + else { + BMEdge *e_step = (BMEdge *)ele_walk; + BLI_assert(ele_walk->head.htype == BM_EDGE); + BM_edge_select_set(em->bm, e_step, true); + BM_elem_flag_disable(e_step, BM_ELEM_TAG); + } } } } } - } - else { - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_TAG)) { - BMEdge *e_walk; - BMW_ITER (e_walk, &walker, e) { - BM_edge_select_set(em->bm, e_walk, true); - BM_elem_flag_disable(e_walk, BM_ELEM_TAG); + else { + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + BMEdge *e_walk; + BMW_ITER (e_walk, &walker, e) { + BM_edge_select_set(em->bm, e_walk, true); + BM_elem_flag_disable(e_walk, BM_ELEM_TAG); + } } } } - } - BMW_end(&walker); + BMW_end(&walker); - EDBM_selectmode_flush(em); - } - else { - BMFace *f; - - BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { - BM_elem_flag_set(f, BM_ELEM_TAG, BM_elem_flag_test(f, BM_ELEM_SELECT)); + EDBM_selectmode_flush(em); } + else { + BMFace *f; - BMW_init(&walker, bm, BMW_ISLAND, - BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP, - BMW_FLAG_TEST_HIDDEN, - BMW_NIL_LAY); + BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { + BM_elem_flag_set(f, BM_ELEM_TAG, BM_elem_flag_test(f, BM_ELEM_SELECT)); + } - BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, BM_ELEM_TAG)) { - BMFace *f_walk; - BMW_ITER (f_walk, &walker, f) { - BM_face_select_set(bm, f_walk, true); - BM_elem_flag_disable(f_walk, BM_ELEM_TAG); + BMW_init(&walker, bm, BMW_ISLAND, + BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP, + BMW_FLAG_TEST_HIDDEN, + BMW_NIL_LAY); + + BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_TAG)) { + BMFace *f_walk; + BMW_ITER (f_walk, &walker, f) { + BM_face_select_set(bm, f_walk, true); + BM_elem_flag_disable(f_walk, BM_ELEM_TAG); + } } } + + BMW_end(&walker); } - BMW_end(&walker); - } + if (delimit) { + select_linked_delimit_end(em); + } + + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - if (delimit) { - select_linked_delimit_end(em); } - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -2872,10 +3079,8 @@ static void edbm_select_linked_pick_ex(BMEditMesh *em, BMElem *ele, bool sel, in static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - Object *obedit = CTX_data_edit_object(C); ViewContext vc; - BMEditMesh *em; - BMesh *bm; + Base *basact = NULL; BMVert *eve; BMEdge *eed; BMFace *efa; @@ -2891,25 +3096,37 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE /* setup view context for argument to callbacks */ em_setup_viewcontext(C, &vc); - em = vc.em; - bm = em->bm; - if (bm->totedge == 0) { - return OPERATOR_CANCELLED; + { + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(vc.view_layer, &objects_len); + bool has_edges = false; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob_iter = objects[ob_index]; + ED_view3d_viewcontext_init_object(&vc, ob_iter); + if (vc.em->bm->totedge) { + has_edges = true; + } + } + MEM_freeN(objects); + if (has_edges == false) { + return OPERATOR_CANCELLED; + } } vc.mval[0] = event->mval[0]; vc.mval[1] = event->mval[1]; /* return warning! */ - if (unified_findnearest(&vc, &eve, &eed, &efa) == 0) { - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - + if (unified_findnearest(&vc, &basact, &eve, &eed, &efa) == 0) { return OPERATOR_CANCELLED; } + ED_view3d_viewcontext_init_object(&vc, basact->object); + BMEditMesh *em = vc.em; + BMesh *bm = em->bm; #ifdef USE_LINKED_SELECT_DEFAULT_HACK - int delimit = select_linked_delimit_default_from_op(op, em->selectmode); + int delimit = select_linked_delimit_default_from_op(op, vc.scene->toolsettings->selectmode); #else int delimit = RNA_enum_get(op->ptr, "delimit"); #endif @@ -2922,9 +3139,11 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE BM_mesh_elem_index_ensure(bm, ele->head.htype); index = EDBM_elem_to_index_any(em, ele); + /* TODO(MULTI_EDIT), index doesn't know which object, + * index selections isn't very common. */ RNA_int_set(op->ptr, "index", index); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, basact->object->data); return OPERATOR_FINISHED; } @@ -2995,47 +3214,56 @@ void MESH_OT_select_linked_pick(wmOperatorType *ot) static int edbm_select_face_by_sides_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMIter iter; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + const bool extend = RNA_boolean_get(op->ptr, "extend"); const int numverts = RNA_int_get(op->ptr, "number"); const int type = RNA_enum_get(op->ptr, "type"); + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); - if (!RNA_boolean_get(op->ptr, "extend")) - EDBM_flag_disable_all(em, BM_ELEM_SELECT); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMIter iter; - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!extend) { + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + } - bool select; + BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) { + bool select; - switch (type) { - case 0: - select = (efa->len < numverts); - break; - case 1: - select = (efa->len == numverts); - break; - case 2: - select = (efa->len > numverts); - break; - case 3: - select = (efa->len != numverts); - break; - default: - BLI_assert(0); - select = false; - break; - } + switch (type) { + case 0: + select = (efa->len < numverts); + break; + case 1: + select = (efa->len == numverts); + break; + case 2: + select = (efa->len > numverts); + break; + case 3: + select = (efa->len != numverts); + break; + default: + BLI_assert(0); + select = false; + break; + } - if (select) { - BM_face_select_set(em->bm, efa, true); + if (select) { + BM_face_select_set(em->bm, efa, true); + } } - } - EDBM_selectmode_flush(em); + EDBM_selectmode_flush(em); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -3075,53 +3303,65 @@ void MESH_OT_select_face_by_sides(wmOperatorType *ot) static int edbm_select_loose_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - BMIter iter; + ViewLayer *view_layer = CTX_data_view_layer(C); + const bool extend = RNA_boolean_get(op->ptr, "extend"); - if (!RNA_boolean_get(op->ptr, "extend")) - EDBM_flag_disable_all(em, BM_ELEM_SELECT); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); - if (em->selectmode & SCE_SELECT_VERTEX) { - BMVert *eve; - BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { - if (!eve->e) { - BM_vert_select_set(bm, eve, true); - } + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMIter iter; + + if (!extend) { + EDBM_flag_disable_all(em, BM_ELEM_SELECT); } - } - if (em->selectmode & SCE_SELECT_EDGE) { - BMEdge *eed; - BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_edge_is_wire(eed)) { - BM_edge_select_set(bm, eed, true); + if (em->selectmode & SCE_SELECT_VERTEX) { + BMVert *eve; + BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { + if (!eve->e) { + BM_vert_select_set(bm, eve, true); + } } } - } - if (em->selectmode & SCE_SELECT_FACE) { - BMFace *efa; - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - BMIter liter; - BMLoop *l; - bool is_loose = true; - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (!BM_edge_is_boundary(l->e)) { - is_loose = false; - break; + if (em->selectmode & SCE_SELECT_EDGE) { + BMEdge *eed; + BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_edge_is_wire(eed)) { + BM_edge_select_set(bm, eed, true); } } - if (is_loose) { - BM_face_select_set(bm, efa, true); + } + + if (em->selectmode & SCE_SELECT_FACE) { + BMFace *efa; + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + BMIter liter; + BMLoop *l; + bool is_loose = true; + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (!BM_edge_is_boundary(l->e)) { + is_loose = false; + break; + } + } + if (is_loose) { + BM_face_select_set(bm, efa, true); + } } } + + EDBM_selectmode_flush(em); + + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } - EDBM_selectmode_flush(em); + MEM_freeN(objects); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; } @@ -3151,28 +3391,46 @@ void MESH_OT_select_loose(wmOperatorType *ot) static int edbm_select_mirror_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); const int axis_flag = RNA_enum_get(op->ptr, "axis"); const bool extend = RNA_boolean_get(op->ptr, "extend"); + Object *obedit_active = CTX_data_edit_object(C); + BMEditMesh *em_active = BKE_editmesh_from_object(obedit_active); + const int select_mode = em_active->bm->selectmode; + int tot_mirr = 0, tot_fail = 0; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totvert && em->bm->totvertsel) { - int totmirr, totfail; + if (em->bm->totvertsel == 0) { + continue; + } + + int tot_mirr_iter = 0, tot_fail_iter = 0; for (int axis = 0; axis < 3; axis++) { if ((1 << axis) & axis_flag) { - EDBM_select_mirrored(em, axis, extend, &totmirr, &totfail); + EDBM_select_mirrored(em, axis, extend, &tot_mirr_iter, &tot_fail_iter); } } - if (totmirr) { + if (tot_mirr_iter) { EDBM_selectmode_flush(em); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } - ED_mesh_report_mirror_ex(op, totmirr, totfail, em->bm->selectmode); + tot_fail += tot_fail_iter; + tot_mirr += tot_mirr_iter; } + MEM_freeN(objects); + if (tot_mirr || tot_fail) { + ED_mesh_report_mirror_ex(op, tot_mirr, tot_fail, select_mode); + } return OPERATOR_FINISHED; } @@ -3204,13 +3462,28 @@ void MESH_OT_select_mirror(wmOperatorType *ot) static int edbm_select_more_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); const bool use_face_step = RNA_boolean_get(op->ptr, "use_face_step"); - EDBM_select_more(em, use_face_step); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + if ((bm->totvertsel == 0) && + (bm->totedgesel == 0) && + (bm->totfacesel == 0)) + { + continue; + } + + EDBM_select_more(em, use_face_step); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -3239,13 +3512,28 @@ void MESH_OT_select_more(wmOperatorType *ot) static int edbm_select_less_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); const bool use_face_step = RNA_boolean_get(op->ptr, "use_face_step"); - EDBM_select_less(em, use_face_step); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + if ((bm->totvertsel == 0) && + (bm->totedgesel == 0) && + (bm->totfacesel == 0)) + { + continue; + } - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + EDBM_select_less(em, use_face_step); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -3458,18 +3746,39 @@ static bool edbm_deselect_nth(BMEditMesh *em, const struct CheckerIntervalParams static int edbm_select_nth_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); struct CheckerIntervalParams op_params; - WM_operator_properties_checker_interval_from_op(op, &op_params); + bool found_active_elt = false; - if (edbm_deselect_nth(em, &op_params) == false) { - BKE_report(op->reports, RPT_ERROR, "Mesh has no active vert/edge/face"); - return OPERATOR_CANCELLED; + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if ((em->bm->totvertsel == 0) && + (em->bm->totedgesel == 0) && + (em->bm->totfacesel == 0)) + { + continue; + } + + if (edbm_deselect_nth(em, &op_params) == true) { + found_active_elt = true; + EDBM_update_generic(em, false, false); + } } + MEM_freeN(objects); - EDBM_update_generic(em, false, false); + if (!found_active_elt) { + BKE_report(op->reports, RPT_ERROR, + (objects_len == 1 ? + "Mesh has no active vert/edge/face" : + "Meshes have no active vert/edge/face")); + return OPERATOR_CANCELLED; + } return OPERATOR_FINISHED; } @@ -3513,34 +3822,42 @@ static int edbm_select_sharp_edges_exec(bContext *C, wmOperator *op) * check the angle between those faces, and if angle is * small enough, select the edge */ - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMIter iter; - BMEdge *e; - BMLoop *l1, *l2; const float angle_limit_cos = cosf(RNA_float_get(op->ptr, "sharpness")); - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false && - BM_edge_loop_pair(e, &l1, &l2)) - { - /* edge has exactly two neighboring faces, check angle */ - const float angle_cos = dot_v3v3(l1->f->no, l2->f->no); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); - if (angle_cos < angle_limit_cos) { - BM_edge_select_set(em->bm, e, true); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMIter iter; + BMEdge *e; + BMLoop *l1, *l2; + + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false && + BM_edge_loop_pair(e, &l1, &l2)) + { + /* edge has exactly two neighboring faces, check angle */ + const float angle_cos = dot_v3v3(l1->f->no, l2->f->no); + + if (angle_cos < angle_limit_cos) { + BM_edge_select_set(em->bm, e, true); + } } } - } - 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); + 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); } - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -3575,59 +3892,70 @@ void MESH_OT_edges_select_sharp(wmOperatorType *ot) static int edbm_select_linked_flat_faces_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - - BLI_LINKSTACK_DECLARE(stack, BMFace *); - - BMIter iter, liter, liter2; - BMFace *f; - BMLoop *l, *l2; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); const float angle_limit_cos = cosf(RNA_float_get(op->ptr, "sharpness")); - BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); - - BLI_LINKSTACK_INIT(stack); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if ((BM_elem_flag_test(f, BM_ELEM_HIDDEN) != 0) || - (BM_elem_flag_test(f, BM_ELEM_TAG) != 0) || - (BM_elem_flag_test(f, BM_ELEM_SELECT) == 0)) - { + if (bm->totfacesel == 0) { continue; } - BLI_assert(BLI_LINKSTACK_SIZE(stack) == 0); + BLI_LINKSTACK_DECLARE(stack, BMFace *); - do { - BM_face_select_set(bm, f, true); + BMIter iter, liter, liter2; + BMFace *f; + BMLoop *l, *l2; - BM_elem_flag_enable(f, BM_ELEM_TAG); + BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - BM_ITER_ELEM (l2, &liter2, l, BM_LOOPS_OF_LOOP) { - float angle_cos; + BLI_LINKSTACK_INIT(stack); - if (BM_elem_flag_test(l2->f, BM_ELEM_TAG) || - BM_elem_flag_test(l2->f, BM_ELEM_HIDDEN)) - { - continue; - } + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if ((BM_elem_flag_test(f, BM_ELEM_HIDDEN) != 0) || + (BM_elem_flag_test(f, BM_ELEM_TAG) != 0) || + (BM_elem_flag_test(f, BM_ELEM_SELECT) == 0)) + { + continue; + } + + BLI_assert(BLI_LINKSTACK_SIZE(stack) == 0); + + do { + BM_face_select_set(bm, f, true); + + BM_elem_flag_enable(f, BM_ELEM_TAG); + + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + BM_ITER_ELEM (l2, &liter2, l, BM_LOOPS_OF_LOOP) { + float angle_cos; - angle_cos = dot_v3v3(f->no, l2->f->no); + if (BM_elem_flag_test(l2->f, BM_ELEM_TAG) || + BM_elem_flag_test(l2->f, BM_ELEM_HIDDEN)) + { + continue; + } + + angle_cos = dot_v3v3(f->no, l2->f->no); - if (angle_cos > angle_limit_cos) { - BLI_LINKSTACK_PUSH(stack, l2->f); + if (angle_cos > angle_limit_cos) { + BLI_LINKSTACK_PUSH(stack, l2->f); + } } } - } - } while ((f = BLI_LINKSTACK_POP(stack))); - } + } while ((f = BLI_LINKSTACK_POP(stack))); + } - BLI_LINKSTACK_FREE(stack); + BLI_LINKSTACK_FREE(stack); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -3662,61 +3990,70 @@ void MESH_OT_faces_select_linked_flat(wmOperatorType *ot) static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMVert *v; - BMEdge *e; - BMIter iter; - + const bool use_extend = RNA_boolean_get(op->ptr, "extend"); 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"); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); - if (!RNA_boolean_get(op->ptr, "extend")) - EDBM_flag_disable_all(em, BM_ELEM_SELECT); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMVert *v; + BMEdge *e; + BMIter iter; - /* Selects isolated verts, and edges that do not have 2 neighboring - * faces - */ + if (!use_extend) { + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + } - if (em->selectmode == SCE_SELECT_FACE) { - BKE_report(op->reports, RPT_ERROR, "Does not work in face selection mode"); - return OPERATOR_CANCELLED; - } + /* Selects isolated verts, and edges that do not have 2 neighboring + * faces + */ - 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); + if (em->selectmode == SCE_SELECT_FACE) { + BKE_report(op->reports, RPT_ERROR, "Does not work in face selection mode"); + MEM_freeN(objects); + 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)) { + if (!BM_vert_is_manifold(v)) { + BM_vert_select_set(em->bm, v, 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_is_over(e, 2)))) - { - /* check we never select perfect edge (in test above) */ - BLI_assert(!(BM_edge_is_manifold(e) && BM_edge_is_contiguous(e))); + 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_is_over(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); + BM_edge_select_set(em->bm, e, true); + } } } } - } - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - EDBM_selectmode_flush(em); + EDBM_selectmode_flush(em); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -3759,53 +4096,66 @@ void MESH_OT_select_non_manifold(wmOperatorType *ot) static int edbm_select_random_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT); const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f; const int seed = WM_operator_properties_select_random_seed_increment_get(op); - BMIter iter; + ViewLayer *view_layer = CTX_data_view_layer(C); - RNG *rng = BLI_rng_new_srandom(seed); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMIter iter; + int seed_iter = seed; - if (em->selectmode & SCE_SELECT_VERTEX) { - BMVert *eve; - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BLI_rng_get_float(rng) < randfac) { - BM_vert_select_set(em->bm, eve, select); + /* This gives a consistent result regardless of object order. */ + if (ob_index) { + seed_iter += BLI_ghashutil_strhash_p(obedit->id.name); + } + + RNG *rng = BLI_rng_new_srandom(seed_iter); + + if (em->selectmode & SCE_SELECT_VERTEX) { + BMVert *eve; + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BLI_rng_get_float(rng) < randfac) { + BM_vert_select_set(em->bm, eve, select); + } } } - } - else if (em->selectmode & SCE_SELECT_EDGE) { - BMEdge *eed; - BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BLI_rng_get_float(rng) < randfac) { - BM_edge_select_set(em->bm, eed, select); + else if (em->selectmode & SCE_SELECT_EDGE) { + BMEdge *eed; + BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { + if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BLI_rng_get_float(rng) < randfac) { + BM_edge_select_set(em->bm, eed, select); + } } } - } - else { - BMFace *efa; - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && BLI_rng_get_float(rng) < randfac) { - BM_face_select_set(em->bm, efa, select); + else { + BMFace *efa; + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && BLI_rng_get_float(rng) < randfac) { + BM_face_select_set(em->bm, efa, select); + } } } - } - BLI_rng_free(rng); + BLI_rng_free(rng); - if (select) { - /* was EDBM_select_flush, but it over select in edge/face mode */ - EDBM_selectmode_flush(em); - } - else { - EDBM_deselect_flush(em); - } + if (select) { + /* was EDBM_select_flush, but it over select in edge/face mode */ + EDBM_selectmode_flush(em); + } + else { + EDBM_deselect_flush(em); + } - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -3855,30 +4205,51 @@ static int edbm_select_ungrouped_poll(bContext *C) static int edbm_select_ungrouped_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); + const bool extend = RNA_boolean_get(op->ptr, "extend"); + ViewLayer *view_layer = CTX_data_view_layer(C); - BMVert *eve; - BMIter iter; + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); - if (!RNA_boolean_get(op->ptr, "extend")) { - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - } + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); + + if (cd_dvert_offset == -1) { + continue; + } - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { - MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); - /* no dv or dv set with no weight */ - if (ELEM(NULL, dv, dv->dw)) { - BM_vert_select_set(em->bm, eve, true); + BMVert *eve; + BMIter iter; + + bool changed = false; + + if (!extend) { + if (em->bm->totvertsel) { + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + changed = true; } } - } - EDBM_selectmode_flush(em); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { + MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); + /* no dv or dv set with no weight */ + if (ELEM(NULL, dv, dv->dw)) { + BM_vert_select_set(em->bm, eve, true); + changed = true; + } + } + } + if (changed) { + EDBM_selectmode_flush(em); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -3998,48 +4369,58 @@ void MESH_OT_select_axis(wmOperatorType *ot) static int edbm_region_to_loop_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *f; - BMEdge *e; - BMIter iter; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (em->bm->totfacesel == 0) { + continue; + } + BMFace *f; + BMEdge *e; + BMIter iter; - BM_mesh_elem_hflag_disable_all(em->bm, BM_EDGE, BM_ELEM_TAG, false); + BM_mesh_elem_hflag_disable_all(em->bm, BM_EDGE, BM_ELEM_TAG, false); - BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { - BMLoop *l1, *l2; - BMIter liter1, liter2; + 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(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; - } + 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); + 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); + 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); + 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); + } } - } - /* If in face-only select mode, switch to edge select mode so that - * an edge-only selection is not inconsistent state */ - if (em->selectmode == SCE_SELECT_FACE) { - em->selectmode = SCE_SELECT_EDGE; - EDBM_selectmode_set(em); - EDBM_selectmode_to_scene(C); - } + /* If in face-only select mode, switch to edge select mode so that + * an edge-only selection is not inconsistent state */ + if (em->selectmode == SCE_SELECT_FACE) { + em->selectmode = SCE_SELECT_EDGE; + EDBM_selectmode_set(em); + EDBM_selectmode_to_scene(C); + } - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -4210,31 +4591,44 @@ static int loop_find_regions(BMEditMesh *em, const bool selbigger) static int edbm_loop_to_region_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMIter iter; - BMFace *f; const bool select_bigger = RNA_boolean_get(op->ptr, "select_bigger"); - /* 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); - const int a = loop_find_regions(em, select_bigger); - const int b = loop_find_regions(em, !select_bigger); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - 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); + if (em->bm->totedgesel == 0) { + continue; + } - EDBM_flag_disable_all(em, BM_ELEM_SELECT); + BMIter iter; + BMFace *f; + + /* 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); + 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); + 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); + EDBM_selectmode_flush(em); + + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + MEM_freeN(objects); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; } |