diff options
-rw-r--r-- | release/scripts/startup/bl_ui/space_image.py | 5 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_ops.c | 215 |
2 files changed, 220 insertions, 0 deletions
diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index f9390cec912..5aadeb1153f 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -115,6 +115,11 @@ class IMAGE_MT_select(Menu): layout.separator() + layout.operator("uv.select_less", text="Less") + layout.operator("uv.select_more", text="More") + + layout.separator() + layout.operator("uv.select_split") diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 7fbcfa1c941..10789f282e7 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -1321,6 +1321,215 @@ static float *uv_sel_co_from_eve(Scene *scene, Image *ima, BMEditMesh *em, BMVer return NULL; } +/* ******************** select more ******************** */ +static void uv_tag_sticky_grow(Scene *scene, Image *ima, BMLoop *start_loop, int sticky, + int cd_loop_uv_offset, int cd_poly_tex_offset) +{ + BMIter iter; + BMLoop *l; + MTexPoly *tf; + MLoopUV *luv1, *luv2; + + BM_elem_flag_enable(start_loop, BM_ELEM_TAG); + + switch (sticky) { + case SI_STICKY_LOC: + luv1 = BM_ELEM_CD_GET_VOID_P(start_loop, cd_loop_uv_offset); + + BM_ITER_ELEM (l, &iter, start_loop->v, BM_LOOPS_OF_VERT) { + tf = BM_ELEM_CD_GET_VOID_P(l->f, cd_poly_tex_offset); + + if (uvedit_face_visible_test(scene, ima, l->f, tf)) { + luv2 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + if (compare_v2v2(luv1->uv, luv2->uv, STD_UV_CONNECT_LIMIT)) { + BM_elem_flag_enable(l, BM_ELEM_TAG); + } + } + } + break; + case SI_STICKY_VERTEX: + BM_ITER_ELEM (l, &iter, start_loop->v, BM_LOOPS_OF_VERT) { + tf = BM_ELEM_CD_GET_VOID_P(l->f, cd_poly_tex_offset); + + if (uvedit_face_visible_test(scene, ima, l->f, tf)) { + BM_elem_flag_enable(l, BM_ELEM_TAG); + } + } + break; + } +} + +static int uv_select_more_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + Image *ima = CTX_data_edit_image(C); + SpaceImage *sima = CTX_wm_space_image(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + BMFace *efa; + BMLoop *l, *lf; + BMIter iter, liter, iterf; + ToolSettings *ts = scene->toolsettings; + int sticky = sima->sticky; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); + + if (ts->uv_flag & UV_SYNC_SELECTION) { + EDBM_select_more(em); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + return OPERATOR_FINISHED; + } + + /* clear tags */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + BM_elem_flag_disable(l->next, BM_ELEM_TAG); + } + } + + /* mark loops to be selected */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); + + if (uvedit_face_visible_test(scene, ima, efa, tf)) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + if (luv->flag & MLOOPUV_VERTSEL) { + if (ts->uv_selectmode == UV_SELECT_FACE) { + BM_ITER_ELEM (lf, &iterf, l->f, BM_LOOPS_OF_FACE) { + uv_tag_sticky_grow(scene, ima, lf, sticky, cd_loop_uv_offset, cd_poly_tex_offset); + } + } + else { + if (l->next) { + uv_tag_sticky_grow(scene, ima, l->next, sticky, cd_loop_uv_offset, cd_poly_tex_offset); + } + if (l->prev) { + uv_tag_sticky_grow(scene, ima, l->prev, sticky, cd_loop_uv_offset, cd_poly_tex_offset); + } + } + } + } + } + } + + /* select tagged loops */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (BM_elem_flag_test(l, BM_ELEM_TAG)) { + uvedit_uv_select_enable(em, scene, l, FALSE); + } + } + } + + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + + return OPERATOR_FINISHED; +} + +static void UV_OT_select_more(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select More"; + ot->description = "Select more UV vertices connected to initial selection"; + ot->idname = "UV_OT_select_more"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* api callbacks */ + ot->exec = uv_select_more_exec; + ot->poll = ED_operator_uvedit; +} + +/* ******************** select less ******************** */ +static int uv_select_less_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + Image *ima = CTX_data_edit_image(C); + SpaceImage *sima = CTX_wm_space_image(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + int sticky = sima->sticky; + + ToolSettings *ts = scene->toolsettings; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); + + if (ts->uv_flag & UV_SYNC_SELECTION) { + EDBM_select_less(em); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + return OPERATOR_FINISHED; + } + + /* clear tags */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + BM_elem_flag_disable(l->next, BM_ELEM_TAG); + } + } + + /* mark loops to be deselected */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); + + if (uvedit_face_visible_test(scene, ima, efa, tf)) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + if (luv->flag & MLOOPUV_VERTSEL) { + if (l->next) { + MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + if (!(luv_next->flag & MLOOPUV_VERTSEL)) { + uv_tag_sticky_grow(scene, ima, l, sticky, cd_loop_uv_offset, cd_poly_tex_offset); + } + } + if (l->prev) { + MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset); + if (!(luv_prev->flag & MLOOPUV_VERTSEL)) { + uv_tag_sticky_grow(scene, ima, l, sticky, cd_loop_uv_offset, cd_poly_tex_offset); + } + } + } + } + } + } + + /* deselect tagged loops */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (BM_elem_flag_test(l, BM_ELEM_TAG)) { + uvedit_uv_select_disable(em, scene, l); + } + } + } + + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + + return OPERATOR_FINISHED; +} + +static void UV_OT_select_less(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Less"; + ot->description = "Deselect UV vertices at the boundary of each selection region"; + ot->idname = "UV_OT_select_less"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* api callbacks */ + ot->exec = uv_select_less_exec; + ot->poll = ED_operator_uvedit; +} + /* ******************** align operator **************** */ static void uv_weld_align(bContext *C, int tool) @@ -4031,6 +4240,8 @@ void ED_operatortypes_uvedit(void) WM_operatortype_append(UV_OT_select_border); WM_operatortype_append(UV_OT_select_lasso); WM_operatortype_append(UV_OT_circle_select); + WM_operatortype_append(UV_OT_select_more); + WM_operatortype_append(UV_OT_select_less); WM_operatortype_append(UV_OT_snap_cursor); WM_operatortype_append(UV_OT_snap_selected); @@ -4103,6 +4314,10 @@ void ED_keymap_uvedit(wmKeyConfig *keyconf) RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select_linked", LKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "extend", TRUE); RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select_linked_pick", LKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", TRUE); + /* select more/less */ + WM_keymap_add_item(keymap, "UV_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0); + WM_keymap_add_item(keymap, "UV_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0); + WM_keymap_add_item(keymap, "UV_OT_unlink_selected", LKEY, KM_PRESS, KM_ALT, 0); kmi = WM_keymap_add_item(keymap, "UV_OT_select_all", AKEY, KM_PRESS, 0, 0); RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE); |