diff options
Diffstat (limited to 'source/blender/editors/mesh/editmesh_select.c')
-rw-r--r-- | source/blender/editors/mesh/editmesh_select.c | 255 |
1 files changed, 194 insertions, 61 deletions
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 87937fd4146..20cebc9d4b9 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" @@ -917,7 +918,7 @@ BMFace *EDBM_face_find_nearest(const struct EvaluationContext *eval_ctx, ViewCon */ static int unified_findnearest( const struct EvaluationContext *eval_ctx, ViewContext *vc, - BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa) + Base **r_base, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa) { BMEditMesh *em = vc->em; static short mval_prev[2] = {-1, -1}; @@ -934,32 +935,70 @@ static int unified_findnearest( BMEdge *eed = NULL; BMFace *efa = 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(eval_ctx->view_layer, &bases_len); /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */ - ED_view3d_backbuf_validate(eval_ctx, 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(eval_ctx, 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(eval_ctx, vc); + + BMFace *efa_test = EDBM_face_find_nearest_ex(eval_ctx, vc, &dist, dist_center_p, true, use_cycle, &efa_zbuf); + if (efa && dist_center_p) { + dist = min_ff(dist_margin, dist_center); + } + if (efa_test) { + *r_base = base_iter; + efa = efa_test; + } + } /* 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(eval_ctx, 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(eval_ctx, vc); + BMEdge *eed_test = EDBM_edge_find_nearest_ex(eval_ctx, vc, &dist, dist_center_p, true, use_cycle, &eed_zbuf); + if (eed && dist_center_p) { + dist = min_ff(dist_margin, dist_center); + } + if (eed_test) { + *r_base = base_iter; + eed = eed_test; + } + } /* bases */ } if ((dist > 0.0f) && em->selectmode & SCE_SELECT_VERTEX) { - eve = EDBM_vert_find_nearest_ex(eval_ctx, 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(eval_ctx, vc); + BMVert *eve_test = EDBM_vert_find_nearest_ex(eval_ctx, vc, &dist, true, use_cycle); + if (eve_test) { + *r_base = base_iter; + eve = eve_test; + } + } /* bases */ } + MEM_SAFE_FREE(bases); + /* return only one of 3 pointers, for frontbuffer redraws */ if (eve) { efa = NULL; eed = NULL; @@ -1804,27 +1843,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_SAFE_FREE(objects); return OPERATOR_FINISHED; } @@ -1896,6 +1951,8 @@ bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect { EvaluationContext eval_ctx; ViewContext vc; + + Base *basact = NULL; BMVert *eve = NULL; BMEdge *eed = NULL; BMFace *efa = NULL; @@ -1906,11 +1963,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(&eval_ctx, &vc, &eve, &eed, &efa)) { + if (unified_findnearest(&eval_ctx, &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(eval_ctx.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_SAFE_FREE(objects); + } if (efa) { if (extend) { @@ -2020,7 +2089,14 @@ bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect } + /* Changing active object is handy since it allows us to + * switch UV layers, vgroups for eg. */ + if (eval_ctx.view_layer->basact != basact) { + eval_ctx.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; } @@ -2242,11 +2318,14 @@ bool EDBM_selectmode_toggle( bContext *C, const short selectmode_new, const int action, const bool use_extend, const bool use_expand) { + EvaluationContext eval_ctx; ToolSettings *ts = CTX_data_tool_settings(C); Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = NULL; bool ret = false; + CTX_data_eval_ctx(C, &eval_ctx); + if (obedit && obedit->type == OB_MESH) { em = BKE_editmesh_from_object(obedit); } @@ -2255,6 +2334,7 @@ bool EDBM_selectmode_toggle( return ret; } + bool only_update = false; switch (action) { case -1: /* already set */ @@ -2262,21 +2342,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; @@ -2285,10 +2368,30 @@ bool EDBM_selectmode_toggle( break; } + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(eval_ctx.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_SAFE_FREE(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); + } } } @@ -2297,24 +2400,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: @@ -2323,10 +2420,18 @@ 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); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data); + } WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL); } + MEM_SAFE_FREE(objects); return ret; } @@ -2528,7 +2633,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; @@ -2594,17 +2699,27 @@ 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); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + +#ifdef USE_LINKED_SELECT_DEFAULT_HACK + const int delimit_init = select_linked_delimit_default_from_op(op, scene->toolsettings->selectmode); +#else + const int delimit_init = RNA_enum_get(op->ptr, "delimit"); +#endif + + 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; BMIter iter; BMWalker walker; -#ifdef USE_LINKED_SELECT_DEFAULT_HACK - int delimit = select_linked_delimit_default_from_op(op, em->selectmode); -#else - int delimit = RNA_enum_get(op->ptr, "delimit"); -#endif + int delimit = delimit_init; select_linked_delimit_validate(bm, &delimit); @@ -2761,6 +2876,10 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } /* objects */ + + MEM_SAFE_FREE(objects); + return OPERATOR_FINISHED; } @@ -2902,11 +3021,9 @@ 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); EvaluationContext eval_ctx; ViewContext vc; - BMEditMesh *em; - BMesh *bm; + Base *basact = NULL; BMVert *eve; BMEdge *eed; BMFace *efa; @@ -2923,25 +3040,39 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE /* setup view context for argument to callbacks */ CTX_data_eval_ctx(C, &eval_ctx); 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(eval_ctx.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_SAFE_FREE(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(&eval_ctx, &vc, &eve, &eed, &efa) == 0) { - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + if (unified_findnearest(&eval_ctx, &vc, &basact, &eve, &eed, &efa) == 0) { + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, basact->object->data); 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 @@ -2954,9 +3085,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; } |