Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/uvedit/uvedit_select.c
| Show First 20 Lines • Show All 192 Lines • ▼ Show 20 Lines | if (select == false) { | ||||
| BM_select_history_validate(em->bm); | BM_select_history_validate(em->bm); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void uvedit_vertex_select_tagged(BMEditMesh *em, | static void uvedit_vertex_select_tagged(BMEditMesh *em, | ||||
| Scene *scene, | Scene *scene, | ||||
| bool select, | bool select, | ||||
| int cd_loop_uv_offset) | const BMUVOffsets offsets) | ||||
| { | { | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { | if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { | ||||
| uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); | uvedit_uv_select_set(scene, em->bm, l, select, false, offsets); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| bool uvedit_face_visible_test_ex(const ToolSettings *ts, BMFace *efa) | bool uvedit_face_visible_test_ex(const ToolSettings *ts, BMFace *efa) | ||||
| { | { | ||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | if (ts->uv_flag & UV_SYNC_SELECTION) { | ||||
| return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0); | return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0); | ||||
| } | } | ||||
| return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT)); | return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT)); | ||||
| } | } | ||||
| bool uvedit_face_visible_test(const Scene *scene, BMFace *efa) | bool uvedit_face_visible_test(const Scene *scene, BMFace *efa) | ||||
| { | { | ||||
| return uvedit_face_visible_test_ex(scene->toolsettings, efa); | return uvedit_face_visible_test_ex(scene->toolsettings, efa); | ||||
| } | } | ||||
| bool uvedit_face_select_test_ex(const ToolSettings *ts, BMFace *efa, const int cd_loop_uv_offset) | bool uvedit_face_select_test_ex(const ToolSettings *ts, BMFace *efa, const BMUVOffsets offsets) | ||||
| { | { | ||||
| BLI_assert(offsets.select_vert >= 0); | |||||
| BLI_assert(offsets.select_edge >= 0); | |||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | if (ts->uv_flag & UV_SYNC_SELECTION) { | ||||
| return BM_elem_flag_test(efa, BM_ELEM_SELECT); | return BM_elem_flag_test(efa, BM_ELEM_SELECT); | ||||
| } | } | ||||
| BMLoop *l; | BMLoop *l; | ||||
| MLoopUV *luv; | |||||
| BMIter liter; | BMIter liter; | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | |||||
| if (ts->uv_selectmode & UV_SELECT_VERTEX) { | if (ts->uv_selectmode & UV_SELECT_VERTEX) { | ||||
| if ((luv->flag & MLOOPUV_VERTSEL) == 0) { | if (!BM_ELEM_CD_GET_BOOL(l, offsets.select_vert)) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| if ((luv->flag & MLOOPUV_EDGESEL) == 0) { | if (!BM_ELEM_CD_GET_BOOL(l, offsets.select_edge)) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| bool uvedit_face_select_test(const Scene *scene, BMFace *efa, const int cd_loop_uv_offset) | bool uvedit_face_select_test(const Scene *scene, BMFace *efa, const BMUVOffsets offsets) | ||||
| { | { | ||||
| return uvedit_face_select_test_ex(scene->toolsettings, efa, cd_loop_uv_offset); | return uvedit_face_select_test_ex(scene->toolsettings, efa, offsets); | ||||
| } | } | ||||
| void uvedit_face_select_set_with_sticky(const Scene *scene, | void uvedit_face_select_set_with_sticky(const Scene *scene, | ||||
| BMEditMesh *em, | BMEditMesh *em, | ||||
| BMFace *efa, | BMFace *efa, | ||||
| const bool select, | const bool select, | ||||
| const bool do_history, | const bool do_history, | ||||
| const int cd_loop_uv_offset) | const BMUVOffsets offsets) | ||||
| { | { | ||||
| const ToolSettings *ts = scene->toolsettings; | const ToolSettings *ts = scene->toolsettings; | ||||
| const char sticky = ts->uv_sticky; | const char sticky = ts->uv_sticky; | ||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | if (ts->uv_flag & UV_SYNC_SELECTION) { | ||||
| uvedit_face_select_set(scene, em->bm, efa, select, do_history, cd_loop_uv_offset); | uvedit_face_select_set(scene, em->bm, efa, select, do_history, offsets); | ||||
| return; | return; | ||||
| } | } | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* NOTE: Previously face selections done in sticky vertex mode selected stray UV vertices | /* NOTE: Previously face selections done in sticky vertex mode selected stray UV vertices | ||||
| * (not part of any face selections). This now uses the sticky location mode logic instead. */ | * (not part of any face selections). This now uses the sticky location mode logic instead. */ | ||||
| switch (sticky) { | switch (sticky) { | ||||
| case SI_STICKY_DISABLE: { | case SI_STICKY_DISABLE: { | ||||
| uvedit_face_select_set(scene, em->bm, efa, select, do_history, cd_loop_uv_offset); | uvedit_face_select_set(scene, em->bm, efa, select, do_history, offsets); | ||||
| break; | break; | ||||
| } | } | ||||
| default: { | default: { | ||||
| /* SI_STICKY_LOC and SI_STICKY_VERTEX modes. */ | /* SI_STICKY_LOC and SI_STICKY_VERTEX modes. */ | ||||
| uvedit_face_select_shared_vert(scene, em, efa, select, do_history, cd_loop_uv_offset); | uvedit_face_select_shared_vert(scene, em, efa, select, do_history, offsets); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void uvedit_face_select_shared_vert(const Scene *scene, | void uvedit_face_select_shared_vert(const Scene *scene, | ||||
| BMEditMesh *em, | BMEditMesh *em, | ||||
| BMFace *efa, | BMFace *efa, | ||||
| const bool select, | const bool select, | ||||
| const bool do_history, | const bool do_history, | ||||
| const int cd_loop_uv_offset) | const BMUVOffsets offsets) | ||||
| { | { | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter liter; | BMIter liter; | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | |||||
| if (select) { | if (select) { | ||||
| luv->flag |= MLOOPUV_EDGESEL; | BM_ELEM_CD_SET_BOOL(l, offsets.select_edge, true); | ||||
| uvedit_uv_select_shared_vert( | uvedit_uv_select_shared_vert(scene, em, l, select, SI_STICKY_LOC, do_history, offsets); | ||||
| scene, em, l, select, SI_STICKY_LOC, do_history, cd_loop_uv_offset); | |||||
| } | } | ||||
| else { | else { | ||||
| luv->flag &= ~MLOOPUV_EDGESEL; | BM_ELEM_CD_SET_BOOL(l, offsets.select_edge, false); | ||||
| if (!uvedit_vert_is_face_select_any_other(scene, l, cd_loop_uv_offset)) { | if (!uvedit_vert_is_face_select_any_other(scene, l, offsets)) { | ||||
| uvedit_uv_select_shared_vert( | uvedit_uv_select_shared_vert(scene, em, l, select, SI_STICKY_LOC, do_history, offsets); | ||||
| scene, em, l, select, SI_STICKY_LOC, do_history, cd_loop_uv_offset); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void uvedit_face_select_set(const Scene *scene, | void uvedit_face_select_set(const Scene *scene, | ||||
| BMesh *bm, | BMesh *bm, | ||||
| BMFace *efa, | BMFace *efa, | ||||
| const bool select, | const bool select, | ||||
| const bool do_history, | const bool do_history, | ||||
| const int cd_loop_uv_offset) | const BMUVOffsets offsets) | ||||
| { | { | ||||
| if (select) { | if (select) { | ||||
| uvedit_face_select_enable(scene, bm, efa, do_history, cd_loop_uv_offset); | uvedit_face_select_enable(scene, bm, efa, do_history, offsets); | ||||
| } | } | ||||
| else { | else { | ||||
| uvedit_face_select_disable(scene, bm, efa, cd_loop_uv_offset); | uvedit_face_select_disable(scene, bm, efa, offsets); | ||||
| } | } | ||||
| } | } | ||||
| void uvedit_face_select_enable( | void uvedit_face_select_enable( | ||||
| const Scene *scene, BMesh *bm, BMFace *efa, const bool do_history, const int cd_loop_uv_offset) | const Scene *scene, BMesh *bm, BMFace *efa, const bool do_history, const BMUVOffsets offsets) | ||||
| { | { | ||||
| BLI_assert(cd_loop_uv_offset >= 0); | BLI_assert(offsets.select_vert >= 0); | ||||
| BLI_assert(offsets.select_edge >= 0); | |||||
| const ToolSettings *ts = scene->toolsettings; | const ToolSettings *ts = scene->toolsettings; | ||||
chrisbblend: Do we need to add?
```
BLI_assert(offsets.select_vert >= 0);
BLI_assert(offsets.select_edge >=… | |||||
Done Inline ActionsCan't hurt. Good idea. Baardaap: Can't hurt. Good idea. | |||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | if (ts->uv_flag & UV_SYNC_SELECTION) { | ||||
| BM_face_select_set(bm, efa, true); | BM_face_select_set(bm, efa, true); | ||||
| if (do_history) { | if (do_history) { | ||||
| BM_select_history_store(bm, (BMElem *)efa); | BM_select_history_store(bm, (BMElem *)efa); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| BMLoop *l; | BMLoop *l; | ||||
| MLoopUV *luv; | |||||
| BMIter liter; | BMIter liter; | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | BM_ELEM_CD_SET_BOOL(l, offsets.select_vert, true); | ||||
| luv->flag |= (MLOOPUV_VERTSEL | MLOOPUV_EDGESEL); | BM_ELEM_CD_SET_BOOL(l, offsets.select_edge, true); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void uvedit_face_select_disable(const Scene *scene, | void uvedit_face_select_disable(const Scene *scene, | ||||
| BMesh *bm, | BMesh *bm, | ||||
| BMFace *efa, | BMFace *efa, | ||||
| const int cd_loop_uv_offset) | const BMUVOffsets offsets) | ||||
| { | { | ||||
| BLI_assert(cd_loop_uv_offset >= 0); | BLI_assert(offsets.select_vert >= 0); | ||||
| BLI_assert(offsets.select_edge >= 0); | |||||
| const ToolSettings *ts = scene->toolsettings; | const ToolSettings *ts = scene->toolsettings; | ||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | if (ts->uv_flag & UV_SYNC_SELECTION) { | ||||
| BM_face_select_set(bm, efa, false); | BM_face_select_set(bm, efa, false); | ||||
| } | } | ||||
| else { | else { | ||||
| BMLoop *l; | BMLoop *l; | ||||
| MLoopUV *luv; | |||||
| BMIter liter; | BMIter liter; | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | BM_ELEM_CD_SET_BOOL(l, offsets.select_vert, false); | ||||
| luv->flag &= ~(MLOOPUV_VERTSEL | MLOOPUV_EDGESEL); | BM_ELEM_CD_SET_BOOL(l, offsets.select_edge, false); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| bool uvedit_edge_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset) | bool uvedit_edge_select_test_ex(const ToolSettings *ts, BMLoop *l, const BMUVOffsets offsets) | ||||
| { | { | ||||
| BLI_assert(offsets.select_vert >= 0); | |||||
| BLI_assert(offsets.select_edge >= 0); | |||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | if (ts->uv_flag & UV_SYNC_SELECTION) { | ||||
| if (ts->selectmode & SCE_SELECT_FACE) { | if (ts->selectmode & SCE_SELECT_FACE) { | ||||
| return BM_elem_flag_test(l->f, BM_ELEM_SELECT); | return BM_elem_flag_test(l->f, BM_ELEM_SELECT); | ||||
| } | } | ||||
| if (ts->selectmode == SCE_SELECT_EDGE) { | if (ts->selectmode == SCE_SELECT_EDGE) { | ||||
| return BM_elem_flag_test(l->e, BM_ELEM_SELECT); | return BM_elem_flag_test(l->e, BM_ELEM_SELECT); | ||||
| } | } | ||||
| return BM_elem_flag_test(l->v, BM_ELEM_SELECT) && | return BM_elem_flag_test(l->v, BM_ELEM_SELECT) && | ||||
| BM_elem_flag_test(l->next->v, BM_ELEM_SELECT); | BM_elem_flag_test(l->next->v, BM_ELEM_SELECT); | ||||
| } | } | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | |||||
| if (ts->uv_selectmode & UV_SELECT_VERTEX) { | if (ts->uv_selectmode & UV_SELECT_VERTEX) { | ||||
| MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); | return BM_ELEM_CD_GET_BOOL(l, offsets.select_vert) && | ||||
| return (luv->flag & MLOOPUV_VERTSEL) && (luv_next->flag & MLOOPUV_VERTSEL); | BM_ELEM_CD_GET_BOOL(l->next, offsets.select_vert); | ||||
| } | } | ||||
| return (luv->flag & MLOOPUV_EDGESEL); | return BM_ELEM_CD_GET_BOOL(l, offsets.select_edge); | ||||
| } | } | ||||
| bool uvedit_edge_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset) | bool uvedit_edge_select_test(const Scene *scene, BMLoop *l, const BMUVOffsets offsets) | ||||
| { | { | ||||
| return uvedit_edge_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset); | return uvedit_edge_select_test_ex(scene->toolsettings, l, offsets); | ||||
| } | } | ||||
| void uvedit_edge_select_set_with_sticky(const Scene *scene, | void uvedit_edge_select_set_with_sticky(const Scene *scene, | ||||
| BMEditMesh *em, | BMEditMesh *em, | ||||
| BMLoop *l, | BMLoop *l, | ||||
| const bool select, | const bool select, | ||||
| const bool do_history, | const bool do_history, | ||||
| const int cd_loop_uv_offset) | const BMUVOffsets offsets) | ||||
| { | { | ||||
| const ToolSettings *ts = scene->toolsettings; | const ToolSettings *ts = scene->toolsettings; | ||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | if (ts->uv_flag & UV_SYNC_SELECTION) { | ||||
| uvedit_edge_select_set(scene, em->bm, l, select, do_history, cd_loop_uv_offset); | uvedit_edge_select_set(scene, em->bm, l, select, do_history, offsets); | ||||
| return; | return; | ||||
| } | } | ||||
| const int sticky = ts->uv_sticky; | const int sticky = ts->uv_sticky; | ||||
| switch (sticky) { | switch (sticky) { | ||||
| case SI_STICKY_DISABLE: { | case SI_STICKY_DISABLE: { | ||||
| if (uvedit_face_visible_test(scene, l->f)) { | if (uvedit_face_visible_test(scene, l->f)) { | ||||
| uvedit_edge_select_set(scene, em->bm, l, select, do_history, cd_loop_uv_offset); | uvedit_edge_select_set(scene, em->bm, l, select, do_history, offsets); | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case SI_STICKY_VERTEX: { | case SI_STICKY_VERTEX: { | ||||
| uvedit_edge_select_shared_vert( | uvedit_edge_select_shared_vert(scene, em, l, select, SI_STICKY_VERTEX, do_history, offsets); | ||||
| scene, em, l, select, SI_STICKY_VERTEX, do_history, cd_loop_uv_offset); | |||||
| break; | break; | ||||
| } | } | ||||
| default: { | default: { | ||||
| /* SI_STICKY_LOC (Fallback) */ | /* SI_STICKY_LOC (Fallback) */ | ||||
| uvedit_edge_select_shared_vert( | uvedit_edge_select_shared_vert(scene, em, l, select, SI_STICKY_LOC, do_history, offsets); | ||||
| scene, em, l, select, SI_STICKY_LOC, do_history, cd_loop_uv_offset); | |||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Selects UV edges and shared vertices according to sticky_flag. | * Selects UV edges and shared vertices according to sticky_flag. | ||||
| * | * | ||||
| * \param sticky_flag: | * \param sticky_flag: | ||||
| * - SI_STICKY_LOC: selects all UV edges that share the same mesh vertices and UV coordinates. | * - SI_STICKY_LOC: selects all UV edges that share the same mesh vertices and UV coordinates. | ||||
| * - SI_STICKY_VERTEX: selects all UV edges sharing the same mesh vertices. | * - SI_STICKY_VERTEX: selects all UV edges sharing the same mesh vertices. | ||||
| */ | */ | ||||
| void uvedit_edge_select_shared_vert(const Scene *scene, | void uvedit_edge_select_shared_vert(const Scene *scene, | ||||
| BMEditMesh *em, | BMEditMesh *em, | ||||
| BMLoop *l, | BMLoop *l, | ||||
| const bool select, | const bool select, | ||||
| const int sticky_flag, | const int sticky_flag, | ||||
| const bool do_history, | const bool do_history, | ||||
| const int cd_loop_uv_offset) | const BMUVOffsets offsets) | ||||
| { | { | ||||
| BLI_assert(ELEM(sticky_flag, SI_STICKY_LOC, SI_STICKY_VERTEX)); | BLI_assert(ELEM(sticky_flag, SI_STICKY_LOC, SI_STICKY_VERTEX)); | ||||
| /* Set edge flags. Rely on this for face visibility checks */ | /* Set edge flags. Rely on this for face visibility checks */ | ||||
| uvedit_edge_select_set_noflush(scene, l, select, sticky_flag, cd_loop_uv_offset); | uvedit_edge_select_set_noflush(scene, l, select, sticky_flag, offsets); | ||||
| /* Vert selections. */ | /* Vert selections. */ | ||||
| BMLoop *l_iter = l; | BMLoop *l_iter = l; | ||||
| do { | do { | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset); | if (select && BM_ELEM_CD_GET_BOOL(l_iter, offsets.select_edge)) { | ||||
| if (select && (luv->flag & MLOOPUV_EDGESEL)) { | uvedit_uv_select_shared_vert(scene, em, l_iter, true, SI_STICKY_LOC, do_history, offsets); | ||||
| uvedit_uv_select_shared_vert( | uvedit_uv_select_shared_vert( | ||||
| scene, em, l_iter, true, SI_STICKY_LOC, do_history, cd_loop_uv_offset); | scene, em, l_iter->next, true, SI_STICKY_LOC, do_history, offsets); | ||||
| uvedit_uv_select_shared_vert( | |||||
| scene, em, l_iter->next, true, SI_STICKY_LOC, do_history, cd_loop_uv_offset); | |||||
| } | } | ||||
| else if (!select && !(luv->flag & MLOOPUV_EDGESEL)) { | else if (!select && !BM_ELEM_CD_GET_BOOL(l_iter, offsets.select_edge)) { | ||||
| if (!uvedit_vert_is_edge_select_any_other(scene, l, cd_loop_uv_offset)) { | if (!uvedit_vert_is_edge_select_any_other(scene, l, offsets)) { | ||||
| uvedit_uv_select_shared_vert( | uvedit_uv_select_shared_vert(scene, em, l_iter, false, SI_STICKY_LOC, do_history, offsets); | ||||
| scene, em, l_iter, false, SI_STICKY_LOC, do_history, cd_loop_uv_offset); | |||||
| } | } | ||||
| if (!uvedit_vert_is_edge_select_any_other(scene, l->next, cd_loop_uv_offset)) { | if (!uvedit_vert_is_edge_select_any_other(scene, l->next, offsets)) { | ||||
| uvedit_uv_select_shared_vert( | uvedit_uv_select_shared_vert( | ||||
| scene, em, l_iter->next, false, SI_STICKY_LOC, do_history, cd_loop_uv_offset); | scene, em, l_iter->next, false, SI_STICKY_LOC, do_history, offsets); | ||||
| } | } | ||||
| } | } | ||||
| } while (((l_iter = l_iter->radial_next) != l) && (sticky_flag != SI_STICKY_LOC)); | } while (((l_iter = l_iter->radial_next) != l) && (sticky_flag != SI_STICKY_LOC)); | ||||
| } | } | ||||
| /* Set edge flags for required UV edges. */ | /* Set edge flags for required UV edges. */ | ||||
| void uvedit_edge_select_set_noflush(const Scene *scene, | void uvedit_edge_select_set_noflush(const Scene *scene, | ||||
| BMLoop *l, | BMLoop *l, | ||||
| const bool select, | const bool select, | ||||
| const int sticky_flag, | const int sticky_flag, | ||||
| const int cd_loop_uv_offset) | const BMUVOffsets offsets) | ||||
| { | { | ||||
| MLoopUV *luv; | BLI_assert(offsets.uv >= 0); | ||||
| BLI_assert(offsets.select_edge >= 0); | |||||
| BMLoop *l_iter = l; | BMLoop *l_iter = l; | ||||
| do { | do { | ||||
| if (uvedit_face_visible_test(scene, l_iter->f)) { | if (uvedit_face_visible_test(scene, l_iter->f)) { | ||||
| if ((sticky_flag == SI_STICKY_VERTEX) || | if ((sticky_flag == SI_STICKY_VERTEX) || | ||||
| BM_loop_uv_share_edge_check(l, l_iter, cd_loop_uv_offset)) { | BM_loop_uv_share_edge_check(l, l_iter, offsets.uv)) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset); | BM_ELEM_CD_SET_BOOL(l_iter, offsets.select_edge, select); | ||||
| SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_EDGESEL); | |||||
| } | } | ||||
| } | } | ||||
| } while (((l_iter = l_iter->radial_next) != l) && (sticky_flag != SI_STICKY_DISABLE)); | } while (((l_iter = l_iter->radial_next) != l) && (sticky_flag != SI_STICKY_DISABLE)); | ||||
| } | } | ||||
| void uvedit_edge_select_set(const Scene *scene, | void uvedit_edge_select_set(const Scene *scene, | ||||
| BMesh *bm, | BMesh *bm, | ||||
| BMLoop *l, | BMLoop *l, | ||||
| const bool select, | const bool select, | ||||
| const bool do_history, | const bool do_history, | ||||
| const int cd_loop_uv_offset) | const BMUVOffsets offsets) | ||||
| { | { | ||||
| if (select) { | if (select) { | ||||
| uvedit_edge_select_enable(scene, bm, l, do_history, cd_loop_uv_offset); | uvedit_edge_select_enable(scene, bm, l, do_history, offsets); | ||||
| } | } | ||||
| else { | else { | ||||
| uvedit_edge_select_disable(scene, bm, l, cd_loop_uv_offset); | uvedit_edge_select_disable(scene, bm, l, offsets); | ||||
| } | } | ||||
| } | } | ||||
| void uvedit_edge_select_enable( | void uvedit_edge_select_enable( | ||||
| const Scene *scene, BMesh *bm, BMLoop *l, const bool do_history, const int cd_loop_uv_offset) | const Scene *scene, BMesh *bm, BMLoop *l, const bool do_history, const BMUVOffsets offsets) | ||||
| { | { | ||||
| const ToolSettings *ts = scene->toolsettings; | const ToolSettings *ts = scene->toolsettings; | ||||
| BLI_assert(offsets.select_vert >= 0); | |||||
| BLI_assert(offsets.select_edge >= 0); | |||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | if (ts->uv_flag & UV_SYNC_SELECTION) { | ||||
| if (ts->selectmode & SCE_SELECT_FACE) { | if (ts->selectmode & SCE_SELECT_FACE) { | ||||
| BM_face_select_set(bm, l->f, true); | BM_face_select_set(bm, l->f, true); | ||||
| } | } | ||||
| else if (ts->selectmode & SCE_SELECT_EDGE) { | else if (ts->selectmode & SCE_SELECT_EDGE) { | ||||
| BM_edge_select_set(bm, l->e, true); | BM_edge_select_set(bm, l->e, true); | ||||
| } | } | ||||
| else { | else { | ||||
| BM_vert_select_set(bm, l->e->v1, true); | BM_vert_select_set(bm, l->e->v1, true); | ||||
| BM_vert_select_set(bm, l->e->v2, true); | BM_vert_select_set(bm, l->e->v2, true); | ||||
| } | } | ||||
| if (do_history) { | if (do_history) { | ||||
| BM_select_history_store(bm, (BMElem *)l->e); | BM_select_history_store(bm, (BMElem *)l->e); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| MLoopUV *luv, *luv_next; | BM_ELEM_CD_SET_BOOL(l, offsets.select_vert, true); | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | BM_ELEM_CD_SET_BOOL(l, offsets.select_edge, true); | ||||
| luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); | BM_ELEM_CD_SET_BOOL(l->next, offsets.select_vert, true); | ||||
| luv->flag |= (MLOOPUV_VERTSEL | MLOOPUV_EDGESEL); | |||||
| luv_next->flag |= MLOOPUV_VERTSEL; | |||||
| } | } | ||||
| } | } | ||||
| void uvedit_edge_select_disable(const Scene *scene, | void uvedit_edge_select_disable(const Scene *scene, | ||||
| BMesh *bm, | BMesh *bm, | ||||
| BMLoop *l, | BMLoop *l, | ||||
| const int cd_loop_uv_offset) | const BMUVOffsets offsets) | ||||
| { | { | ||||
| const ToolSettings *ts = scene->toolsettings; | const ToolSettings *ts = scene->toolsettings; | ||||
| BLI_assert(offsets.select_vert >= 0); | |||||
| BLI_assert(offsets.select_edge >= 0); | |||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | if (ts->uv_flag & UV_SYNC_SELECTION) { | ||||
| if (ts->selectmode & SCE_SELECT_FACE) { | if (ts->selectmode & SCE_SELECT_FACE) { | ||||
| BM_face_select_set(bm, l->f, false); | BM_face_select_set(bm, l->f, false); | ||||
| } | } | ||||
| else if (ts->selectmode & SCE_SELECT_EDGE) { | else if (ts->selectmode & SCE_SELECT_EDGE) { | ||||
| BM_edge_select_set(bm, l->e, false); | BM_edge_select_set(bm, l->e, false); | ||||
| } | } | ||||
| else { | else { | ||||
| BM_vert_select_set(bm, l->e->v1, false); | BM_vert_select_set(bm, l->e->v1, false); | ||||
| BM_vert_select_set(bm, l->e->v2, false); | BM_vert_select_set(bm, l->e->v2, false); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| MLoopUV *luv, *luv_next; | BM_ELEM_CD_SET_BOOL(l, offsets.select_edge, false); | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | |||||
| luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); | |||||
| luv->flag &= ~MLOOPUV_EDGESEL; | |||||
| if ((ts->uv_selectmode & UV_SELECT_VERTEX) == 0) { | if ((ts->uv_selectmode & UV_SELECT_VERTEX) == 0) { | ||||
| /* Deselect UV vertex if not part of another edge selection */ | /* Deselect UV vertex if not part of another edge selection */ | ||||
| MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset); | if (!BM_ELEM_CD_GET_BOOL(l->next, offsets.select_edge)) { | ||||
| if (!(luv_next->flag & MLOOPUV_EDGESEL)) { | BM_ELEM_CD_SET_BOOL(l->next, offsets.select_vert, false); | ||||
| luv_next->flag &= ~MLOOPUV_VERTSEL; | |||||
| } | } | ||||
| if (!(luv_prev->flag & MLOOPUV_EDGESEL)) { | if (!BM_ELEM_CD_GET_BOOL(l->prev, offsets.select_edge)) { | ||||
| luv->flag &= ~MLOOPUV_VERTSEL; | BM_ELEM_CD_SET_BOOL(l, offsets.select_vert, false); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| luv_next->flag &= ~MLOOPUV_VERTSEL; | BM_ELEM_CD_SET_BOOL(l, offsets.select_vert, false); | ||||
| luv->flag &= ~MLOOPUV_VERTSEL; | BM_ELEM_CD_SET_BOOL(l->next, offsets.select_vert, false); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| bool uvedit_uv_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset) | bool uvedit_uv_select_test_ex(const ToolSettings *ts, BMLoop *l, const BMUVOffsets offsets) | ||||
| { | { | ||||
| BLI_assert(offsets.select_vert >= 0); | |||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | if (ts->uv_flag & UV_SYNC_SELECTION) { | ||||
| if (ts->selectmode & SCE_SELECT_FACE) { | if (ts->selectmode & SCE_SELECT_FACE) { | ||||
| return BM_elem_flag_test_bool(l->f, BM_ELEM_SELECT); | return BM_elem_flag_test_bool(l->f, BM_ELEM_SELECT); | ||||
| } | } | ||||
| if (ts->selectmode & SCE_SELECT_EDGE) { | if (ts->selectmode & SCE_SELECT_EDGE) { | ||||
| /* Are you looking for `uvedit_edge_select_test(...)` instead? */ | /* Are you looking for `uvedit_edge_select_test(...)` instead? */ | ||||
| } | } | ||||
| return BM_elem_flag_test_bool(l->v, BM_ELEM_SELECT); | return BM_elem_flag_test_bool(l->v, BM_ELEM_SELECT); | ||||
| } | } | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | |||||
| if (ts->selectmode & SCE_SELECT_FACE) { | if (ts->selectmode & SCE_SELECT_FACE) { | ||||
| /* Are you looking for `uvedit_face_select_test(...)` instead? */ | /* Are you looking for `uvedit_face_select_test(...)` instead? */ | ||||
| } | } | ||||
| if (ts->selectmode & SCE_SELECT_EDGE) { | if (ts->selectmode & SCE_SELECT_EDGE) { | ||||
| /* Are you looking for `uvedit_edge_select_test(...)` instead? */ | /* Are you looking for `uvedit_edge_select_test(...)` instead? */ | ||||
| } | } | ||||
| return (luv->flag & MLOOPUV_VERTSEL) != 0; | return BM_ELEM_CD_GET_BOOL(l, offsets.select_vert); | ||||
| } | } | ||||
| bool uvedit_uv_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset) | bool uvedit_uv_select_test(const Scene *scene, BMLoop *l, const BMUVOffsets offsets) | ||||
| { | { | ||||
| return uvedit_uv_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset); | return uvedit_uv_select_test_ex(scene->toolsettings, l, offsets); | ||||
| } | } | ||||
| void uvedit_uv_select_set_with_sticky(const Scene *scene, | void uvedit_uv_select_set_with_sticky(const Scene *scene, | ||||
| BMEditMesh *em, | BMEditMesh *em, | ||||
| BMLoop *l, | BMLoop *l, | ||||
| const bool select, | const bool select, | ||||
| const bool do_history, | const bool do_history, | ||||
| const int cd_loop_uv_offset) | const BMUVOffsets offsets) | ||||
| { | { | ||||
| const ToolSettings *ts = scene->toolsettings; | const ToolSettings *ts = scene->toolsettings; | ||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | if (ts->uv_flag & UV_SYNC_SELECTION) { | ||||
| uvedit_uv_select_set(scene, em->bm, l, select, do_history, cd_loop_uv_offset); | uvedit_uv_select_set(scene, em->bm, l, select, do_history, offsets); | ||||
| return; | return; | ||||
| } | } | ||||
| const int sticky = ts->uv_sticky; | const int sticky = ts->uv_sticky; | ||||
| switch (sticky) { | switch (sticky) { | ||||
| case SI_STICKY_DISABLE: { | case SI_STICKY_DISABLE: { | ||||
| if (uvedit_face_visible_test(scene, l->f)) { | if (uvedit_face_visible_test(scene, l->f)) { | ||||
| uvedit_uv_select_set(scene, em->bm, l, select, do_history, cd_loop_uv_offset); | uvedit_uv_select_set(scene, em->bm, l, select, do_history, offsets); | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case SI_STICKY_VERTEX: { | case SI_STICKY_VERTEX: { | ||||
| uvedit_uv_select_shared_vert( | uvedit_uv_select_shared_vert(scene, em, l, select, SI_STICKY_VERTEX, do_history, offsets); | ||||
| scene, em, l, select, SI_STICKY_VERTEX, do_history, cd_loop_uv_offset); | |||||
| break; | break; | ||||
| } | } | ||||
| default: { | default: { | ||||
| /* SI_STICKY_LOC. */ | /* SI_STICKY_LOC. */ | ||||
| uvedit_uv_select_shared_vert( | uvedit_uv_select_shared_vert(scene, em, l, select, SI_STICKY_LOC, do_history, offsets); | ||||
| scene, em, l, select, SI_STICKY_LOC, do_history, cd_loop_uv_offset); | |||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Selects shared UVs based on #sticky_flag. | * Selects shared UVs based on #sticky_flag. | ||||
| * | * | ||||
| * \param sticky_flag: Type of sticky selection : | * \param sticky_flag: Type of sticky selection : | ||||
| * - SI_STICKY_LOC: selects all UVs sharing same mesh vertex and UV coordinates. | * - SI_STICKY_LOC: selects all UVs sharing same mesh vertex and UV coordinates. | ||||
| * - SI_STICKY_VERTEX: selects all UVs sharing same mesh vertex. | * - SI_STICKY_VERTEX: selects all UVs sharing same mesh vertex. | ||||
| */ | */ | ||||
| void uvedit_uv_select_shared_vert(const Scene *scene, | void uvedit_uv_select_shared_vert(const Scene *scene, | ||||
| BMEditMesh *em, | BMEditMesh *em, | ||||
| BMLoop *l, | BMLoop *l, | ||||
| const bool select, | const bool select, | ||||
| const int sticky_flag, | const int sticky_flag, | ||||
| const bool do_history, | const bool do_history, | ||||
| const int cd_loop_uv_offset) | const BMUVOffsets offsets) | ||||
| { | { | ||||
| BLI_assert(ELEM(sticky_flag, SI_STICKY_LOC, SI_STICKY_VERTEX)); | BLI_assert(ELEM(sticky_flag, SI_STICKY_LOC, SI_STICKY_VERTEX)); | ||||
| BLI_assert(offsets.uv >= 0); | |||||
| BMEdge *e_first, *e_iter; | BMEdge *e_first, *e_iter; | ||||
| e_first = e_iter = l->e; | e_first = e_iter = l->e; | ||||
| do { | do { | ||||
| BMLoop *l_radial_iter = e_iter->l; | BMLoop *l_radial_iter = e_iter->l; | ||||
| if (!l_radial_iter) { | if (!l_radial_iter) { | ||||
| continue; /* Skip wire edges with no loops. */ | continue; /* Skip wire edges with no loops. */ | ||||
| } | } | ||||
| do { | do { | ||||
| if (l_radial_iter->v == l->v) { | if (l_radial_iter->v == l->v) { | ||||
| if (uvedit_face_visible_test(scene, l_radial_iter->f)) { | if (uvedit_face_visible_test(scene, l_radial_iter->f)) { | ||||
| bool do_select = false; | bool do_select = false; | ||||
| if (sticky_flag == SI_STICKY_VERTEX) { | if (sticky_flag == SI_STICKY_VERTEX) { | ||||
| do_select = true; | do_select = true; | ||||
| } | } | ||||
| else if (BM_loop_uv_share_vert_check(l, l_radial_iter, cd_loop_uv_offset)) { | else if (BM_loop_uv_share_vert_check(l, l_radial_iter, offsets.uv)) { | ||||
| do_select = true; | do_select = true; | ||||
| } | } | ||||
| if (do_select) { | if (do_select) { | ||||
| uvedit_uv_select_set( | uvedit_uv_select_set(scene, em->bm, l_radial_iter, select, do_history, offsets); | ||||
| scene, em->bm, l_radial_iter, select, do_history, cd_loop_uv_offset); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } while ((l_radial_iter = l_radial_iter->radial_next) != e_iter->l); | } while ((l_radial_iter = l_radial_iter->radial_next) != e_iter->l); | ||||
| } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, l->v)) != e_first); | } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, l->v)) != e_first); | ||||
| } | } | ||||
| void uvedit_uv_select_set(const Scene *scene, | void uvedit_uv_select_set(const Scene *scene, | ||||
| BMesh *bm, | BMesh *bm, | ||||
| BMLoop *l, | BMLoop *l, | ||||
| const bool select, | const bool select, | ||||
| const bool do_history, | const bool do_history, | ||||
| const int cd_loop_uv_offset) | const BMUVOffsets offsets) | ||||
| { | { | ||||
| if (select) { | if (select) { | ||||
| uvedit_uv_select_enable(scene, bm, l, do_history, cd_loop_uv_offset); | uvedit_uv_select_enable(scene, bm, l, do_history, offsets); | ||||
| } | } | ||||
| else { | else { | ||||
| uvedit_uv_select_disable(scene, bm, l, cd_loop_uv_offset); | uvedit_uv_select_disable(scene, bm, l, offsets); | ||||
| } | } | ||||
| } | } | ||||
| void uvedit_uv_select_enable( | void uvedit_uv_select_enable( | ||||
| const Scene *scene, BMesh *bm, BMLoop *l, const bool do_history, const int cd_loop_uv_offset) | const Scene *scene, BMesh *bm, BMLoop *l, const bool do_history, const BMUVOffsets offsets) | ||||
| { | { | ||||
| const ToolSettings *ts = scene->toolsettings; | const ToolSettings *ts = scene->toolsettings; | ||||
| BLI_assert(offsets.select_vert >= 0); | |||||
| if (ts->selectmode & SCE_SELECT_EDGE) { | if (ts->selectmode & SCE_SELECT_EDGE) { | ||||
| /* Are you looking for `uvedit_edge_select_set(...)` instead? */ | /* Are you looking for `uvedit_edge_select_set(...)` instead? */ | ||||
| } | } | ||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | if (ts->uv_flag & UV_SYNC_SELECTION) { | ||||
| if (ts->selectmode & SCE_SELECT_FACE) { | if (ts->selectmode & SCE_SELECT_FACE) { | ||||
| BM_face_select_set(bm, l->f, true); | BM_face_select_set(bm, l->f, true); | ||||
| } | } | ||||
| else { | else { | ||||
| BM_vert_select_set(bm, l->v, true); | BM_vert_select_set(bm, l->v, true); | ||||
| } | } | ||||
| if (do_history) { | if (do_history) { | ||||
| BM_select_history_store(bm, (BMElem *)l->v); | BM_select_history_store(bm, (BMElem *)l->v); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | BM_ELEM_CD_SET_BOOL(l, offsets.select_vert, true); | ||||
| luv->flag |= MLOOPUV_VERTSEL; | |||||
| } | } | ||||
| } | } | ||||
| void uvedit_uv_select_disable(const Scene *scene, | void uvedit_uv_select_disable(const Scene *scene, BMesh *bm, BMLoop *l, const BMUVOffsets offsets) | ||||
| BMesh *bm, | |||||
| BMLoop *l, | |||||
| const int cd_loop_uv_offset) | |||||
| { | { | ||||
| const ToolSettings *ts = scene->toolsettings; | const ToolSettings *ts = scene->toolsettings; | ||||
| BLI_assert(offsets.select_vert >= 0); | |||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | if (ts->uv_flag & UV_SYNC_SELECTION) { | ||||
| if (ts->selectmode & SCE_SELECT_FACE) { | if (ts->selectmode & SCE_SELECT_FACE) { | ||||
| BM_face_select_set(bm, l->f, false); | BM_face_select_set(bm, l->f, false); | ||||
| } | } | ||||
| else { | else { | ||||
| BM_vert_select_set(bm, l->v, false); | BM_vert_select_set(bm, l->v, false); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | BM_ELEM_CD_SET_BOOL(l, offsets.select_vert, false); | ||||
| luv->flag &= ~MLOOPUV_VERTSEL; | |||||
| } | } | ||||
| } | } | ||||
| static BMLoop *uvedit_loop_find_other_radial_loop_with_visible_face(const Scene *scene, | static BMLoop *uvedit_loop_find_other_radial_loop_with_visible_face(const Scene *scene, | ||||
| BMLoop *l_src, | BMLoop *l_src, | ||||
| const int cd_loop_uv_offset) | const BMUVOffsets offsets) | ||||
| { | { | ||||
| BLI_assert(offsets.uv >= 0); | |||||
| BMLoop *l_other = NULL; | BMLoop *l_other = NULL; | ||||
| BMLoop *l_iter = l_src->radial_next; | BMLoop *l_iter = l_src->radial_next; | ||||
| if (l_iter != l_src) { | if (l_iter != l_src) { | ||||
| do { | do { | ||||
| if (uvedit_face_visible_test(scene, l_iter->f) && | if (uvedit_face_visible_test(scene, l_iter->f) && | ||||
| BM_loop_uv_share_edge_check(l_src, l_iter, cd_loop_uv_offset)) { | BM_loop_uv_share_edge_check(l_src, l_iter, offsets.uv)) { | ||||
| /* Check UV's are contiguous. */ | /* Check UV's are contiguous. */ | ||||
| if (l_other == NULL) { | if (l_other == NULL) { | ||||
| l_other = l_iter; | l_other = l_iter; | ||||
| } | } | ||||
| else { | else { | ||||
| /* Only use when there is a single alternative. */ | /* Only use when there is a single alternative. */ | ||||
| l_other = NULL; | l_other = NULL; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } while ((l_iter = l_iter->radial_next) != l_src); | } while ((l_iter = l_iter->radial_next) != l_src); | ||||
| } | } | ||||
| return l_other; | return l_other; | ||||
| } | } | ||||
| static BMLoop *uvedit_loop_find_other_boundary_loop_with_visible_face(const Scene *scene, | static BMLoop *uvedit_loop_find_other_boundary_loop_with_visible_face(const Scene *scene, | ||||
| BMLoop *l_edge, | BMLoop *l_edge, | ||||
| BMVert *v_pivot, | BMVert *v_pivot, | ||||
| const int cd_loop_uv_offset) | const BMUVOffsets offsets) | ||||
| { | { | ||||
| BLI_assert(uvedit_loop_find_other_radial_loop_with_visible_face( | BLI_assert(uvedit_loop_find_other_radial_loop_with_visible_face(scene, l_edge, offsets) == NULL); | ||||
| scene, l_edge, cd_loop_uv_offset) == NULL); | |||||
| BMLoop *l_step = l_edge; | BMLoop *l_step = l_edge; | ||||
| l_step = (l_step->v == v_pivot) ? l_step->prev : l_step->next; | l_step = (l_step->v == v_pivot) ? l_step->prev : l_step->next; | ||||
| BMLoop *l_step_last = NULL; | BMLoop *l_step_last = NULL; | ||||
| do { | do { | ||||
| BLI_assert(BM_vert_in_edge(l_step->e, v_pivot)); | BLI_assert(BM_vert_in_edge(l_step->e, v_pivot)); | ||||
| l_step_last = l_step; | l_step_last = l_step; | ||||
| l_step = uvedit_loop_find_other_radial_loop_with_visible_face( | l_step = uvedit_loop_find_other_radial_loop_with_visible_face(scene, l_step, offsets); | ||||
| scene, l_step, cd_loop_uv_offset); | |||||
| if (l_step) { | if (l_step) { | ||||
| l_step = (l_step->v == v_pivot) ? l_step->prev : l_step->next; | l_step = (l_step->v == v_pivot) ? l_step->prev : l_step->next; | ||||
| } | } | ||||
| } while (l_step != NULL); | } while (l_step != NULL); | ||||
| if (l_step_last != NULL) { | if (l_step_last != NULL) { | ||||
| BLI_assert(uvedit_loop_find_other_radial_loop_with_visible_face( | BLI_assert(uvedit_loop_find_other_radial_loop_with_visible_face(scene, l_step_last, offsets) == | ||||
| scene, l_step_last, cd_loop_uv_offset) == NULL); | NULL); | ||||
| } | } | ||||
| return l_step_last; | return l_step_last; | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Find Nearest Elements | /** \name Find Nearest Elements | ||||
| * \{ */ | * \{ */ | ||||
| bool uv_find_nearest_edge( | bool uv_find_nearest_edge( | ||||
| Scene *scene, Object *obedit, const float co[2], const float penalty, UvNearestHit *hit) | Scene *scene, Object *obedit, const float co[2], const float penalty, UvNearestHit *hit) | ||||
| { | { | ||||
| BLI_assert((hit->scale[0] > 0.0f) && (hit->scale[1] > 0.0f)); | BLI_assert((hit->scale[0] > 0.0f) && (hit->scale[1] > 0.0f)); | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| MLoopUV *luv, *luv_next; | float *luv, *luv_next; | ||||
| int i; | int i; | ||||
| bool found = false; | bool found = false; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | ||||
| BLI_assert(offsets.uv >= 0); | |||||
| BM_mesh_elem_index_ensure(em->bm, BM_VERT); | BM_mesh_elem_index_ensure(em->bm, BM_VERT); | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { | BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | luv = BM_ELEM_CD_GET_VOID_P(l, offsets.uv); | ||||
| luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); | luv_next = BM_ELEM_CD_GET_VOID_P(l->next, offsets.uv); | ||||
| float delta[2]; | float delta[2]; | ||||
| closest_to_line_segment_v2(delta, co, luv->uv, luv_next->uv); | closest_to_line_segment_v2(delta, co, luv, luv_next); | ||||
| sub_v2_v2(delta, co); | sub_v2_v2(delta, co); | ||||
| mul_v2_v2(delta, hit->scale); | mul_v2_v2(delta, hit->scale); | ||||
| float dist_test_sq = len_squared_v2(delta); | float dist_test_sq = len_squared_v2(delta); | ||||
| /* Ensures that successive selection attempts will select other edges sharing the same | /* Ensures that successive selection attempts will select other edges sharing the same | ||||
| * UV coordinates as the previous selection. */ | * UV coordinates as the previous selection. */ | ||||
| if ((penalty != 0.0f) && uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) { | if ((penalty != 0.0f) && uvedit_edge_select_test(scene, l, offsets)) { | ||||
| dist_test_sq = square_f(sqrtf(dist_test_sq) + penalty); | dist_test_sq = square_f(sqrtf(dist_test_sq) + penalty); | ||||
| } | } | ||||
| if (dist_test_sq < hit->dist_sq) { | if (dist_test_sq < hit->dist_sq) { | ||||
| hit->ob = obedit; | hit->ob = obedit; | ||||
| hit->efa = efa; | hit->efa = efa; | ||||
| hit->l = l; | hit->l = l; | ||||
| Show All 24 Lines | |||||
| bool uv_find_nearest_face_ex( | bool uv_find_nearest_face_ex( | ||||
| Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit, const bool only_in_face) | Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit, const bool only_in_face) | ||||
| { | { | ||||
| BLI_assert((hit->scale[0] > 0.0f) && (hit->scale[1] > 0.0f)); | BLI_assert((hit->scale[0] > 0.0f) && (hit->scale[1] > 0.0f)); | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| bool found = false; | bool found = false; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| BMIter iter; | BMIter iter; | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | |||||
| bool uv_find_nearest_face_multi( | bool uv_find_nearest_face_multi( | ||||
| Scene *scene, Object **objects, const uint objects_len, const float co[2], UvNearestHit *hit) | Scene *scene, Object **objects, const uint objects_len, const float co[2], UvNearestHit *hit) | ||||
| { | { | ||||
| return uv_find_nearest_face_multi_ex(scene, objects, objects_len, co, hit, false); | return uv_find_nearest_face_multi_ex(scene, objects, objects_len, co, hit, false); | ||||
| } | } | ||||
| static bool uv_nearest_between(const BMLoop *l, const float co[2], const int cd_loop_uv_offset) | static bool uv_nearest_between(const BMLoop *l, const float co[2], const int cd_loop_uv_offset) | ||||
| { | { | ||||
| const float *uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset))->uv; | const float *uv_prev = BM_ELEM_CD_GET_FLOAT_P(l->prev, cd_loop_uv_offset); | ||||
| const float *uv_curr = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv; | const float *uv_curr = BM_ELEM_CD_GET_FLOAT_P(l, cd_loop_uv_offset); | ||||
| const float *uv_next = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset))->uv; | const float *uv_next = BM_ELEM_CD_GET_FLOAT_P(l->next, cd_loop_uv_offset); | ||||
| return ((line_point_side_v2(uv_prev, uv_curr, co) > 0.0f) && | return ((line_point_side_v2(uv_prev, uv_curr, co) > 0.0f) && | ||||
| (line_point_side_v2(uv_next, uv_curr, co) <= 0.0f)); | (line_point_side_v2(uv_next, uv_curr, co) <= 0.0f)); | ||||
| } | } | ||||
| bool uv_find_nearest_vert( | bool uv_find_nearest_vert( | ||||
| Scene *scene, Object *obedit, float const co[2], const float penalty_dist, UvNearestHit *hit) | Scene *scene, Object *obedit, float const co[2], const float penalty_dist, UvNearestHit *hit) | ||||
| { | { | ||||
| BLI_assert((hit->scale[0] > 0.0f) && (hit->scale[1] > 0.0f)); | BLI_assert((hit->scale[0] > 0.0f) && (hit->scale[1] > 0.0f)); | ||||
| bool found = false; | bool found = false; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMIter iter; | BMIter iter; | ||||
| BM_mesh_elem_index_ensure(em->bm, BM_VERT); | BM_mesh_elem_index_ensure(em->bm, BM_VERT); | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | ||||
| BLI_assert(offsets.uv >= 0); | |||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BMIter liter; | BMIter liter; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| int i; | int i; | ||||
| BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { | BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | float *luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv); | ||||
| float delta[2]; | float delta[2]; | ||||
| sub_v2_v2v2(delta, co, luv->uv); | sub_v2_v2v2(delta, co, luv); | ||||
| mul_v2_v2(delta, hit->scale); | mul_v2_v2(delta, hit->scale); | ||||
| float dist_test_sq = len_squared_v2(delta); | float dist_test_sq = len_squared_v2(delta); | ||||
| /* Ensures that successive selection attempts will select other vertices sharing the same | /* Ensures that successive selection attempts will select other vertices sharing the same | ||||
| * UV coordinates */ | * UV coordinates */ | ||||
| if ((penalty_dist != 0.0f) && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { | if ((penalty_dist != 0.0f) && uvedit_uv_select_test(scene, l, offsets)) { | ||||
| dist_test_sq = square_f(sqrtf(dist_test_sq) + penalty_dist); | dist_test_sq = square_f(sqrtf(dist_test_sq) + penalty_dist); | ||||
| } | } | ||||
| if (dist_test_sq <= hit->dist_sq) { | if (dist_test_sq <= hit->dist_sq) { | ||||
| if (dist_test_sq == hit->dist_sq) { | if (dist_test_sq == hit->dist_sq) { | ||||
| if (!uv_nearest_between(l, co, cd_loop_uv_offset)) { | if (!uv_nearest_between(l, co, offsets.uv)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| } | } | ||||
| hit->dist_sq = dist_test_sq; | hit->dist_sq = dist_test_sq; | ||||
| hit->ob = obedit; | hit->ob = obedit; | ||||
| hit->efa = efa; | hit->efa = efa; | ||||
| Show All 31 Lines | static bool uvedit_nearest_uv(const Scene *scene, | ||||
| float *dist_sq, | float *dist_sq, | ||||
| float r_uv[2]) | float r_uv[2]) | ||||
| { | { | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| BMIter iter; | BMIter iter; | ||||
| BMFace *efa; | BMFace *efa; | ||||
| const float *uv_best = NULL; | const float *uv_best = NULL; | ||||
| float dist_best = *dist_sq; | float dist_best = *dist_sq; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | ||||
| BLI_assert(offsets.uv >= 0); | |||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BMLoop *l_iter, *l_first; | BMLoop *l_iter, *l_first; | ||||
| l_iter = l_first = BM_FACE_FIRST_LOOP(efa); | l_iter = l_first = BM_FACE_FIRST_LOOP(efa); | ||||
| do { | do { | ||||
| if (ignore_selected && uvedit_uv_select_test(scene, l_iter, cd_loop_uv_offset)) { | if (ignore_selected && uvedit_uv_select_test(scene, l_iter, offsets)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| const float *uv = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv; | const float *uv = BM_ELEM_CD_GET_FLOAT_P(l_iter, offsets.uv); | ||||
| float co_tmp[2]; | float co_tmp[2]; | ||||
| mul_v2_v2v2(co_tmp, scale, uv); | mul_v2_v2v2(co_tmp, scale, uv); | ||||
| const float dist_test = len_squared_v2v2(co, co_tmp); | const float dist_test = len_squared_v2v2(co, co_tmp); | ||||
| if (dist_best > dist_test) { | if (dist_best > dist_test) { | ||||
| dist_best = dist_test; | dist_best = dist_test; | ||||
| uv_best = uv; | uv_best = uv; | ||||
| } | } | ||||
| } while ((l_iter = l_iter->next) != l_first); | } while ((l_iter = l_iter->next) != l_first); | ||||
| ▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | |||||
| * \{ */ | * \{ */ | ||||
| BMLoop *uv_find_nearest_loop_from_vert(struct Scene *scene, | BMLoop *uv_find_nearest_loop_from_vert(struct Scene *scene, | ||||
| struct Object *obedit, | struct Object *obedit, | ||||
| struct BMVert *v, | struct BMVert *v, | ||||
| const float co[2]) | const float co[2]) | ||||
| { | { | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| BMIter liter; | BMIter liter; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMLoop *l_found = NULL; | BMLoop *l_found = NULL; | ||||
| float dist_best_sq = FLT_MAX; | float dist_best_sq = FLT_MAX; | ||||
| BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { | BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { | ||||
| if (!uvedit_face_visible_test(scene, l->f)) { | if (!uvedit_face_visible_test(scene, l->f)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | const float *luv = BM_ELEM_CD_GET_FLOAT_P(l, cd_loop_uv_offset); | ||||
| const float dist_test_sq = len_squared_v2v2(co, luv->uv); | const float dist_test_sq = len_squared_v2v2(co, luv); | ||||
| if (dist_test_sq < dist_best_sq) { | if (dist_test_sq < dist_best_sq) { | ||||
| dist_best_sq = dist_test_sq; | dist_best_sq = dist_test_sq; | ||||
| l_found = l; | l_found = l; | ||||
| } | } | ||||
| } | } | ||||
| return l_found; | return l_found; | ||||
| } | } | ||||
| BMLoop *uv_find_nearest_loop_from_edge(struct Scene *scene, | BMLoop *uv_find_nearest_loop_from_edge(struct Scene *scene, | ||||
| struct Object *obedit, | struct Object *obedit, | ||||
| struct BMEdge *e, | struct BMEdge *e, | ||||
| const float co[2]) | const float co[2]) | ||||
| { | { | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| BLI_assert(cd_loop_uv_offset >= 0); | |||||
| BMIter eiter; | BMIter eiter; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMLoop *l_found = NULL; | BMLoop *l_found = NULL; | ||||
| float dist_best_sq = FLT_MAX; | float dist_best_sq = FLT_MAX; | ||||
| BM_ITER_ELEM (l, &eiter, e, BM_LOOPS_OF_EDGE) { | BM_ITER_ELEM (l, &eiter, e, BM_LOOPS_OF_EDGE) { | ||||
| if (!uvedit_face_visible_test(scene, l->f)) { | if (!uvedit_face_visible_test(scene, l->f)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | const float *luv = BM_ELEM_CD_GET_FLOAT_P(l, cd_loop_uv_offset); | ||||
| const MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); | const float *luv_next = BM_ELEM_CD_GET_FLOAT_P(l->next, cd_loop_uv_offset); | ||||
| const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv); | const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv, luv_next); | ||||
| if (dist_test_sq < dist_best_sq) { | if (dist_test_sq < dist_best_sq) { | ||||
| dist_best_sq = dist_test_sq; | dist_best_sq = dist_test_sq; | ||||
| l_found = l; | l_found = l; | ||||
| } | } | ||||
| } | } | ||||
| return l_found; | return l_found; | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Helper functions for UV selection. | /** \name Helper functions for UV selection. | ||||
| * \{ */ | * \{ */ | ||||
| bool uvedit_vert_is_edge_select_any_other(const Scene *scene, | bool uvedit_vert_is_edge_select_any_other(const Scene *scene, BMLoop *l, const BMUVOffsets offsets) | ||||
| BMLoop *l, | |||||
| const int cd_loop_uv_offset) | |||||
| { | { | ||||
| BLI_assert(offsets.uv >= 0); | |||||
| BMEdge *e_iter = l->e; | BMEdge *e_iter = l->e; | ||||
| do { | do { | ||||
| BMLoop *l_radial_iter = e_iter->l, *l_other; | BMLoop *l_radial_iter = e_iter->l, *l_other; | ||||
| do { | do { | ||||
| if (uvedit_face_visible_test(scene, l_radial_iter->f)) { | if (uvedit_face_visible_test(scene, l_radial_iter->f)) { | ||||
| /* Use #l_other to check if the uvs are connected (share the same uv coordinates) | /* Use #l_other to check if the uvs are connected (share the same uv coordinates) | ||||
| * and #l_radial_iter for the actual edge selection test. */ | * and #l_radial_iter for the actual edge selection test. */ | ||||
| l_other = (l_radial_iter->v != l->v) ? l_radial_iter->next : l_radial_iter; | l_other = (l_radial_iter->v != l->v) ? l_radial_iter->next : l_radial_iter; | ||||
| if (BM_loop_uv_share_vert_check(l, l_other, cd_loop_uv_offset) && | if (BM_loop_uv_share_vert_check(l, l_other, offsets.uv) && | ||||
| uvedit_edge_select_test(scene, l_radial_iter, cd_loop_uv_offset)) { | uvedit_edge_select_test(scene, l_radial_iter, offsets)) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| } while ((l_radial_iter = l_radial_iter->radial_next) != e_iter->l); | } while ((l_radial_iter = l_radial_iter->radial_next) != e_iter->l); | ||||
| } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, l->v)) != l->e); | } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, l->v)) != l->e); | ||||
| return false; | return false; | ||||
| } | } | ||||
| bool uvedit_vert_is_face_select_any_other(const Scene *scene, | bool uvedit_vert_is_face_select_any_other(const Scene *scene, BMLoop *l, const BMUVOffsets offsets) | ||||
| BMLoop *l, | |||||
| const int cd_loop_uv_offset) | |||||
| { | { | ||||
| BLI_assert(offsets.uv >= 0); | |||||
| BMIter liter; | BMIter liter; | ||||
| BMLoop *l_iter; | BMLoop *l_iter; | ||||
| BM_ITER_ELEM (l_iter, &liter, l->v, BM_LOOPS_OF_VERT) { | BM_ITER_ELEM (l_iter, &liter, l->v, BM_LOOPS_OF_VERT) { | ||||
| if (!uvedit_face_visible_test(scene, l_iter->f) || (l_iter->f == l->f)) { | if (!uvedit_face_visible_test(scene, l_iter->f) || (l_iter->f == l->f)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (BM_loop_uv_share_vert_check(l, l_iter, cd_loop_uv_offset) && | if (BM_loop_uv_share_vert_check(l, l_iter, offsets.uv) && | ||||
| uvedit_face_select_test(scene, l_iter->f, cd_loop_uv_offset)) { | uvedit_face_select_test(scene, l_iter->f, offsets)) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| bool uvedit_vert_is_all_other_faces_selected(const Scene *scene, | bool uvedit_vert_is_all_other_faces_selected(const Scene *scene, | ||||
| BMLoop *l, | BMLoop *l, | ||||
| const int cd_loop_uv_offset) | const BMUVOffsets offsets) | ||||
| { | { | ||||
| BLI_assert(offsets.uv >= 0); | |||||
| BMIter liter; | BMIter liter; | ||||
| BMLoop *l_iter; | BMLoop *l_iter; | ||||
| BM_ITER_ELEM (l_iter, &liter, l->v, BM_LOOPS_OF_VERT) { | BM_ITER_ELEM (l_iter, &liter, l->v, BM_LOOPS_OF_VERT) { | ||||
| if (!uvedit_face_visible_test(scene, l_iter->f) || (l_iter->f == l->f)) { | if (!uvedit_face_visible_test(scene, l_iter->f) || (l_iter->f == l->f)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (BM_loop_uv_share_vert_check(l, l_iter, cd_loop_uv_offset) && | if (BM_loop_uv_share_vert_check(l, l_iter, offsets.uv) && | ||||
| !uvedit_face_select_test(scene, l_iter->f, cd_loop_uv_offset)) { | !uvedit_face_select_test(scene, l_iter->f, offsets)) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| /** | static void bm_clear_uv_vert_selection(const Scene *scene, BMesh *bm, const BMUVOffsets offsets) | ||||
| * Clear specified UV flag (vert/edge/pinned). | |||||
| */ | |||||
| static void bm_uv_flag_clear(const Scene *scene, | |||||
| BMesh *bm, | |||||
| const int flag, | |||||
| const int cd_loop_uv_offset) | |||||
| { | { | ||||
| if (offsets.select_vert == -1) { | |||||
| return; | |||||
| } | |||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | BM_ELEM_CD_SET_BOOL(l, offsets.select_vert, false); | ||||
| luv->flag &= ~flag; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name UV Select-Mode Flushing | /** \name UV Select-Mode Flushing | ||||
| * | * | ||||
| * \{ */ | * \{ */ | ||||
| void ED_uvedit_selectmode_flush(const Scene *scene, BMEditMesh *em) | void ED_uvedit_selectmode_flush(const Scene *scene, BMEditMesh *em) | ||||
| { | { | ||||
| const ToolSettings *ts = scene->toolsettings; | const ToolSettings *ts = scene->toolsettings; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const char *active_uv_name = CustomData_get_active_layer_name(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| BM_uv_map_ensure_vert_select_attr(em->bm, active_uv_name); | |||||
| BM_uv_map_ensure_edge_select_attr(em->bm, active_uv_name); | |||||
| const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | |||||
| BLI_assert((ts->uv_flag & UV_SYNC_SELECTION) == 0); | BLI_assert((ts->uv_flag & UV_SYNC_SELECTION) == 0); | ||||
| UNUSED_VARS_NDEBUG(ts); | UNUSED_VARS_NDEBUG(ts); | ||||
| /* Vertex Mode only. */ | /* Vertex Mode only. */ | ||||
| if (ts->uv_selectmode & UV_SELECT_VERTEX) { | if (ts->uv_selectmode & UV_SELECT_VERTEX) { | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| MLoopUV *luv, *luv_next; | bool edge_selected = BM_ELEM_CD_GET_BOOL(l, offsets.select_vert) && | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | BM_ELEM_CD_GET_BOOL(l->next, offsets.select_vert); | ||||
| luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); | BM_ELEM_CD_SET_BOOL(l, offsets.select_edge, edge_selected); | ||||
| if ((luv->flag & MLOOPUV_VERTSEL) && (luv_next->flag & MLOOPUV_VERTSEL)) { | |||||
| luv->flag |= MLOOPUV_EDGESEL; | |||||
| } | |||||
| else { | |||||
| luv->flag &= ~MLOOPUV_EDGESEL; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name UV Flush selection (up/down) | /** \name UV Flush selection (up/down) | ||||
| * \{ */ | * \{ */ | ||||
| void uvedit_select_flush(const Scene *scene, BMEditMesh *em) | void uvedit_select_flush(const Scene *scene, BMEditMesh *em) | ||||
| { | { | ||||
| /* Careful when using this in face select mode. | /* Careful when using this in face select mode. | ||||
| * For face selections with sticky mode enabled, this can create invalid selection states. */ | * For face selections with sticky mode enabled, this can create invalid selection states. */ | ||||
| const ToolSettings *ts = scene->toolsettings; | const ToolSettings *ts = scene->toolsettings; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const char *active_uv_name = CustomData_get_active_layer_name(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| BM_uv_map_ensure_edge_select_attr(em->bm, active_uv_name); | |||||
| BM_uv_map_ensure_vert_select_attr(em->bm, active_uv_name); | |||||
| const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | |||||
| BLI_assert((ts->uv_flag & UV_SYNC_SELECTION) == 0); | BLI_assert((ts->uv_flag & UV_SYNC_SELECTION) == 0); | ||||
| UNUSED_VARS_NDEBUG(ts); | UNUSED_VARS_NDEBUG(ts); | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| MLoopUV *luv, *luv_next; | if (BM_ELEM_CD_GET_BOOL(l, offsets.select_vert) && | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | BM_ELEM_CD_GET_BOOL(l->next, offsets.select_vert)) { | ||||
| luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); | BM_ELEM_CD_SET_BOOL(l, offsets.select_edge, true); | ||||
| if ((luv->flag & MLOOPUV_VERTSEL) && (luv_next->flag & MLOOPUV_VERTSEL)) { | |||||
| luv->flag |= MLOOPUV_EDGESEL; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void uvedit_deselect_flush(const Scene *scene, BMEditMesh *em) | void uvedit_deselect_flush(const Scene *scene, BMEditMesh *em) | ||||
| { | { | ||||
| const ToolSettings *ts = scene->toolsettings; | const ToolSettings *ts = scene->toolsettings; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const char *active_uv_name = CustomData_get_active_layer_name(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| BM_uv_map_ensure_edge_select_attr(em->bm, active_uv_name); | |||||
| BM_uv_map_ensure_vert_select_attr(em->bm, active_uv_name); | |||||
| const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | |||||
| BLI_assert((ts->uv_flag & UV_SYNC_SELECTION) == 0); | BLI_assert((ts->uv_flag & UV_SYNC_SELECTION) == 0); | ||||
| UNUSED_VARS_NDEBUG(ts); | UNUSED_VARS_NDEBUG(ts); | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| MLoopUV *luv, *luv_next; | if ((!BM_ELEM_CD_GET_BOOL(l, offsets.select_vert)) || | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | (!BM_ELEM_CD_GET_BOOL(l->next, offsets.select_vert))) { | ||||
| luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); | BM_ELEM_CD_SET_BOOL(l, offsets.select_edge, false); | ||||
| if (luv->flag & MLOOPUV_EDGESEL) { | |||||
| if (!(luv->flag & MLOOPUV_VERTSEL) || !(luv_next->flag & MLOOPUV_VERTSEL)) { | |||||
| luv->flag &= ~MLOOPUV_EDGESEL; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Edge Loop Select | /** \name Edge Loop Select | ||||
| * \{ */ | * \{ */ | ||||
| /** Mode for selecting edge loops at boundaries. */ | /** Mode for selecting edge loops at boundaries. */ | ||||
| enum eUVEdgeLoopBoundaryMode { | enum eUVEdgeLoopBoundaryMode { | ||||
| /** Delimit at face corners (don't walk over multiple edges in the same face). */ | /** Delimit at face corners (don't walk over multiple edges in the same face). */ | ||||
| UV_EDGE_LOOP_BOUNDARY_LOOP = 1, | UV_EDGE_LOOP_BOUNDARY_LOOP = 1, | ||||
| /** Don't delimit, walk over the all connected boundary loops. */ | /** Don't delimit, walk over the all connected boundary loops. */ | ||||
| UV_EDGE_LOOP_BOUNDARY_ALL = 2, | UV_EDGE_LOOP_BOUNDARY_ALL = 2, | ||||
| }; | }; | ||||
| static BMLoop *bm_select_edgeloop_double_side_next(const Scene *scene, | static BMLoop *bm_select_edgeloop_double_side_next(const Scene *scene, | ||||
| BMLoop *l_step, | BMLoop *l_step, | ||||
| BMVert *v_from, | BMVert *v_from, | ||||
| const int cd_loop_uv_offset) | const BMUVOffsets offsets) | ||||
| { | { | ||||
| if (l_step->f->len == 4) { | if (l_step->f->len == 4) { | ||||
| BMVert *v_from_next = BM_edge_other_vert(l_step->e, v_from); | BMVert *v_from_next = BM_edge_other_vert(l_step->e, v_from); | ||||
| BMLoop *l_step_over = (v_from == l_step->v) ? l_step->next : l_step->prev; | BMLoop *l_step_over = (v_from == l_step->v) ? l_step->next : l_step->prev; | ||||
| l_step_over = uvedit_loop_find_other_radial_loop_with_visible_face( | l_step_over = uvedit_loop_find_other_radial_loop_with_visible_face( | ||||
| scene, l_step_over, cd_loop_uv_offset); | scene, l_step_over, offsets); | ||||
| if (l_step_over) { | if (l_step_over) { | ||||
| return (l_step_over->v == v_from_next) ? l_step_over->prev : l_step_over->next; | return (l_step_over->v == v_from_next) ? l_step_over->prev : l_step_over->next; | ||||
| } | } | ||||
| } | } | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| static BMLoop *bm_select_edgeloop_single_side_next(const Scene *scene, | static BMLoop *bm_select_edgeloop_single_side_next(const Scene *scene, | ||||
| BMLoop *l_step, | BMLoop *l_step, | ||||
| BMVert *v_from, | BMVert *v_from, | ||||
| const int cd_loop_uv_offset) | const BMUVOffsets offsets) | ||||
| { | { | ||||
| BMVert *v_from_next = BM_edge_other_vert(l_step->e, v_from); | BMVert *v_from_next = BM_edge_other_vert(l_step->e, v_from); | ||||
| return uvedit_loop_find_other_boundary_loop_with_visible_face( | return uvedit_loop_find_other_boundary_loop_with_visible_face( | ||||
| scene, l_step, v_from_next, cd_loop_uv_offset); | scene, l_step, v_from_next, offsets); | ||||
| } | } | ||||
| /* TODO(@campbellbarton): support this in the BMesh API, as we have for clearing other types. */ | /* TODO(@campbellbarton): support this in the BMesh API, as we have for clearing other types. */ | ||||
| static void bm_loop_tags_clear(BMesh *bm) | static void bm_loop_tags_clear(BMesh *bm) | ||||
| { | { | ||||
| BMIter iter; | BMIter iter; | ||||
| BMFace *f; | BMFace *f; | ||||
| BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { | ||||
| BMIter liter; | BMIter liter; | ||||
| BMLoop *l_iter; | BMLoop *l_iter; | ||||
| BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) { | ||||
| BM_elem_flag_disable(l_iter, BM_ELEM_TAG); | BM_elem_flag_disable(l_iter, BM_ELEM_TAG); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Tag all loops which should be selected, the caller must select. | * Tag all loops which should be selected, the caller must select. | ||||
| */ | */ | ||||
| static void uv_select_edgeloop_double_side_tag(const Scene *scene, | static void uv_select_edgeloop_double_side_tag(const Scene *scene, | ||||
| BMEditMesh *em, | BMEditMesh *em, | ||||
| BMLoop *l_init_pair[2], | BMLoop *l_init_pair[2], | ||||
| const int cd_loop_uv_offset) | const BMUVOffsets offsets) | ||||
| { | { | ||||
| bm_loop_tags_clear(em->bm); | bm_loop_tags_clear(em->bm); | ||||
| for (int side = 0; side < 2; side++) { | for (int side = 0; side < 2; side++) { | ||||
| BMLoop *l_step_pair[2] = {l_init_pair[0], l_init_pair[1]}; | BMLoop *l_step_pair[2] = {l_init_pair[0], l_init_pair[1]}; | ||||
| BMVert *v_from = side ? l_step_pair[0]->e->v1 : l_step_pair[0]->e->v2; | BMVert *v_from = side ? l_step_pair[0]->e->v1 : l_step_pair[0]->e->v2; | ||||
| /* Disable since we start from the same edge. */ | /* Disable since we start from the same edge. */ | ||||
| BM_elem_flag_disable(l_step_pair[0], BM_ELEM_TAG); | BM_elem_flag_disable(l_step_pair[0], BM_ELEM_TAG); | ||||
| BM_elem_flag_disable(l_step_pair[1], BM_ELEM_TAG); | BM_elem_flag_disable(l_step_pair[1], BM_ELEM_TAG); | ||||
| while ((l_step_pair[0] != NULL) && (l_step_pair[1] != NULL)) { | while ((l_step_pair[0] != NULL) && (l_step_pair[1] != NULL)) { | ||||
| if (!uvedit_face_visible_test(scene, l_step_pair[0]->f) || | if (!uvedit_face_visible_test(scene, l_step_pair[0]->f) || | ||||
| !uvedit_face_visible_test(scene, l_step_pair[1]->f) || | !uvedit_face_visible_test(scene, l_step_pair[1]->f) || | ||||
| /* Check loops have not diverged. */ | /* Check loops have not diverged. */ | ||||
| (uvedit_loop_find_other_radial_loop_with_visible_face( | (uvedit_loop_find_other_radial_loop_with_visible_face(scene, l_step_pair[0], offsets) != | ||||
| scene, l_step_pair[0], cd_loop_uv_offset) != l_step_pair[1])) { | l_step_pair[1])) { | ||||
| break; | break; | ||||
| } | } | ||||
| BLI_assert(l_step_pair[0]->e == l_step_pair[1]->e); | BLI_assert(l_step_pair[0]->e == l_step_pair[1]->e); | ||||
| BM_elem_flag_enable(l_step_pair[0], BM_ELEM_TAG); | BM_elem_flag_enable(l_step_pair[0], BM_ELEM_TAG); | ||||
| BM_elem_flag_enable(l_step_pair[1], BM_ELEM_TAG); | BM_elem_flag_enable(l_step_pair[1], BM_ELEM_TAG); | ||||
| BMVert *v_from_next = BM_edge_other_vert(l_step_pair[0]->e, v_from); | BMVert *v_from_next = BM_edge_other_vert(l_step_pair[0]->e, v_from); | ||||
| /* Walk over both sides, ensure they keep on the same edge. */ | /* Walk over both sides, ensure they keep on the same edge. */ | ||||
| for (int i = 0; i < ARRAY_SIZE(l_step_pair); i++) { | for (int i = 0; i < ARRAY_SIZE(l_step_pair); i++) { | ||||
| l_step_pair[i] = bm_select_edgeloop_double_side_next( | l_step_pair[i] = bm_select_edgeloop_double_side_next( | ||||
| scene, l_step_pair[i], v_from, cd_loop_uv_offset); | scene, l_step_pair[i], v_from, offsets); | ||||
| } | } | ||||
| if ((l_step_pair[0] && BM_elem_flag_test(l_step_pair[0], BM_ELEM_TAG)) || | if ((l_step_pair[0] && BM_elem_flag_test(l_step_pair[0], BM_ELEM_TAG)) || | ||||
| (l_step_pair[1] && BM_elem_flag_test(l_step_pair[1], BM_ELEM_TAG))) { | (l_step_pair[1] && BM_elem_flag_test(l_step_pair[1], BM_ELEM_TAG))) { | ||||
| break; | break; | ||||
| } | } | ||||
| v_from = v_from_next; | v_from = v_from_next; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Tag all loops which should be selected, the caller must select. | * Tag all loops which should be selected, the caller must select. | ||||
| * | * | ||||
| * \param r_count_by_select: Count the number of unselected and selected loops, | * \param r_count_by_select: Count the number of unselected and selected loops, | ||||
| * this is needed to implement cycling between #eUVEdgeLoopBoundaryMode. | * this is needed to implement cycling between #eUVEdgeLoopBoundaryMode. | ||||
| */ | */ | ||||
| static void uv_select_edgeloop_single_side_tag(const Scene *scene, | static void uv_select_edgeloop_single_side_tag(const Scene *scene, | ||||
| BMEditMesh *em, | BMEditMesh *em, | ||||
| BMLoop *l_init, | BMLoop *l_init, | ||||
| const int cd_loop_uv_offset, | const BMUVOffsets offsets, | ||||
| enum eUVEdgeLoopBoundaryMode boundary_mode, | enum eUVEdgeLoopBoundaryMode boundary_mode, | ||||
| int r_count_by_select[2]) | int r_count_by_select[2]) | ||||
| { | { | ||||
| if (r_count_by_select) { | if (r_count_by_select) { | ||||
| r_count_by_select[0] = r_count_by_select[1] = 0; | r_count_by_select[0] = r_count_by_select[1] = 0; | ||||
| } | } | ||||
| bm_loop_tags_clear(em->bm); | bm_loop_tags_clear(em->bm); | ||||
| for (int side = 0; side < 2; side++) { | for (int side = 0; side < 2; side++) { | ||||
| BMLoop *l_step = l_init; | BMLoop *l_step = l_init; | ||||
| BMVert *v_from = side ? l_step->e->v1 : l_step->e->v2; | BMVert *v_from = side ? l_step->e->v1 : l_step->e->v2; | ||||
| /* Disable since we start from the same edge. */ | /* Disable since we start from the same edge. */ | ||||
| BM_elem_flag_disable(l_step, BM_ELEM_TAG); | BM_elem_flag_disable(l_step, BM_ELEM_TAG); | ||||
| while (l_step != NULL) { | while (l_step != NULL) { | ||||
| if (!uvedit_face_visible_test(scene, l_step->f) || | if (!uvedit_face_visible_test(scene, l_step->f) || | ||||
| /* Check the boundary is still a boundary. */ | /* Check the boundary is still a boundary. */ | ||||
| (uvedit_loop_find_other_radial_loop_with_visible_face( | (uvedit_loop_find_other_radial_loop_with_visible_face(scene, l_step, offsets) != NULL)) { | ||||
| scene, l_step, cd_loop_uv_offset) != NULL)) { | |||||
| break; | break; | ||||
| } | } | ||||
| if (r_count_by_select != NULL) { | if (r_count_by_select != NULL) { | ||||
| r_count_by_select[uvedit_edge_select_test(scene, l_step, cd_loop_uv_offset)] += 1; | r_count_by_select[uvedit_edge_select_test(scene, l_step, offsets)] += 1; | ||||
| /* Early exit when mixed could be optional if needed. */ | /* Early exit when mixed could be optional if needed. */ | ||||
| if (r_count_by_select[0] && r_count_by_select[1]) { | if (r_count_by_select[0] && r_count_by_select[1]) { | ||||
| r_count_by_select[0] = r_count_by_select[1] = -1; | r_count_by_select[0] = r_count_by_select[1] = -1; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| BM_elem_flag_enable(l_step, BM_ELEM_TAG); | BM_elem_flag_enable(l_step, BM_ELEM_TAG); | ||||
| BMVert *v_from_next = BM_edge_other_vert(l_step->e, v_from); | BMVert *v_from_next = BM_edge_other_vert(l_step->e, v_from); | ||||
| BMFace *f_step_prev = l_step->f; | BMFace *f_step_prev = l_step->f; | ||||
| l_step = bm_select_edgeloop_single_side_next(scene, l_step, v_from, cd_loop_uv_offset); | l_step = bm_select_edgeloop_single_side_next(scene, l_step, v_from, offsets); | ||||
| if (l_step && BM_elem_flag_test(l_step, BM_ELEM_TAG)) { | if (l_step && BM_elem_flag_test(l_step, BM_ELEM_TAG)) { | ||||
| break; | break; | ||||
| } | } | ||||
| if (boundary_mode == UV_EDGE_LOOP_BOUNDARY_LOOP) { | if (boundary_mode == UV_EDGE_LOOP_BOUNDARY_LOOP) { | ||||
| /* Don't allow walking over the face. */ | /* Don't allow walking over the face. */ | ||||
| if (f_step_prev == l_step->f) { | if (f_step_prev == l_step->f) { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| v_from = v_from_next; | v_from = v_from_next; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static int uv_select_edgeloop(Scene *scene, Object *obedit, UvNearestHit *hit, const bool extend) | static int uv_select_edgeloop(Scene *scene, Object *obedit, UvNearestHit *hit, const bool extend) | ||||
| { | { | ||||
| const ToolSettings *ts = scene->toolsettings; | const ToolSettings *ts = scene->toolsettings; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| bool select; | bool select; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const char *active_uv_name = CustomData_get_active_layer_name(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| BM_uv_map_ensure_vert_select_attr(em->bm, active_uv_name); | |||||
| BM_uv_map_ensure_edge_select_attr(em->bm, active_uv_name); | |||||
| const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | |||||
| if (extend) { | if (extend) { | ||||
| select = !uvedit_edge_select_test(scene, hit->l, cd_loop_uv_offset); | select = !uvedit_edge_select_test(scene, hit->l, offsets); | ||||
| } | } | ||||
| else { | else { | ||||
| select = true; | select = true; | ||||
| } | } | ||||
| BMLoop *l_init_pair[2] = { | BMLoop *l_init_pair[2] = { | ||||
| hit->l, | hit->l, | ||||
| uvedit_loop_find_other_radial_loop_with_visible_face(scene, hit->l, cd_loop_uv_offset), | uvedit_loop_find_other_radial_loop_with_visible_face(scene, hit->l, offsets), | ||||
| }; | }; | ||||
| /* When selecting boundaries, support cycling between selection modes. */ | /* When selecting boundaries, support cycling between selection modes. */ | ||||
| enum eUVEdgeLoopBoundaryMode boundary_mode = UV_EDGE_LOOP_BOUNDARY_LOOP; | enum eUVEdgeLoopBoundaryMode boundary_mode = UV_EDGE_LOOP_BOUNDARY_LOOP; | ||||
| /* Tag all loops that are part of the edge loop (select after). | /* Tag all loops that are part of the edge loop (select after). | ||||
| * This is done so we can */ | * This is done so we can */ | ||||
| if (l_init_pair[1] == NULL) { | if (l_init_pair[1] == NULL) { | ||||
| int count_by_select[2]; | int count_by_select[2]; | ||||
| /* If the loops selected toggle the boundaries. */ | /* If the loops selected toggle the boundaries. */ | ||||
| uv_select_edgeloop_single_side_tag( | uv_select_edgeloop_single_side_tag( | ||||
| scene, em, l_init_pair[0], cd_loop_uv_offset, boundary_mode, count_by_select); | scene, em, l_init_pair[0], offsets, boundary_mode, count_by_select); | ||||
| if (count_by_select[!select] == 0) { | if (count_by_select[!select] == 0) { | ||||
| boundary_mode = UV_EDGE_LOOP_BOUNDARY_ALL; | boundary_mode = UV_EDGE_LOOP_BOUNDARY_ALL; | ||||
| /* If the boundary is selected, toggle back to the loop. */ | /* If the boundary is selected, toggle back to the loop. */ | ||||
| uv_select_edgeloop_single_side_tag( | uv_select_edgeloop_single_side_tag( | ||||
| scene, em, l_init_pair[0], cd_loop_uv_offset, boundary_mode, count_by_select); | scene, em, l_init_pair[0], offsets, boundary_mode, count_by_select); | ||||
| if (count_by_select[!select] == 0) { | if (count_by_select[!select] == 0) { | ||||
| boundary_mode = UV_EDGE_LOOP_BOUNDARY_LOOP; | boundary_mode = UV_EDGE_LOOP_BOUNDARY_LOOP; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (l_init_pair[1] == NULL) { | if (l_init_pair[1] == NULL) { | ||||
| uv_select_edgeloop_single_side_tag( | uv_select_edgeloop_single_side_tag(scene, em, l_init_pair[0], offsets, boundary_mode, NULL); | ||||
| scene, em, l_init_pair[0], cd_loop_uv_offset, boundary_mode, NULL); | |||||
| } | } | ||||
| else { | else { | ||||
| uv_select_edgeloop_double_side_tag(scene, em, l_init_pair, cd_loop_uv_offset); | uv_select_edgeloop_double_side_tag(scene, em, l_init_pair, offsets); | ||||
| } | } | ||||
| /* Apply the selection. */ | /* Apply the selection. */ | ||||
| if (!extend) { | if (!extend) { | ||||
| uv_select_all_perform(scene, obedit, SEL_DESELECT); | uv_select_all_perform(scene, obedit, SEL_DESELECT); | ||||
| } | } | ||||
| /* Select all tagged loops. */ | /* Select all tagged loops. */ | ||||
| { | { | ||||
| BMIter iter; | BMIter iter; | ||||
| BMFace *f; | BMFace *f; | ||||
| BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| BMIter liter; | BMIter liter; | ||||
| BMLoop *l_iter; | BMLoop *l_iter; | ||||
| BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) { | ||||
| if (BM_elem_flag_test(l_iter, BM_ELEM_TAG)) { | if (BM_elem_flag_test(l_iter, BM_ELEM_TAG)) { | ||||
| if (ts->uv_selectmode == UV_SELECT_VERTEX) { | if (ts->uv_selectmode == UV_SELECT_VERTEX) { | ||||
| uvedit_uv_select_set_with_sticky(scene, em, l_iter, select, false, cd_loop_uv_offset); | uvedit_uv_select_set_with_sticky(scene, em, l_iter, select, false, offsets); | ||||
| uvedit_uv_select_set_with_sticky( | uvedit_uv_select_set_with_sticky(scene, em, l_iter->next, select, false, offsets); | ||||
| scene, em, l_iter->next, select, false, cd_loop_uv_offset); | |||||
| } | } | ||||
| else { | else { | ||||
| uvedit_edge_select_set_with_sticky( | uvedit_edge_select_set_with_sticky(scene, em, l_iter, select, false, offsets); | ||||
| scene, em, l_iter, select, false, cd_loop_uv_offset); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return select ? 1 : -1; | return select ? 1 : -1; | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Face Loop Select | /** \name Face Loop Select | ||||
| * \{ */ | * \{ */ | ||||
| static int uv_select_faceloop(Scene *scene, Object *obedit, UvNearestHit *hit, const bool extend) | static int uv_select_faceloop(Scene *scene, Object *obedit, UvNearestHit *hit, const bool extend) | ||||
| { | { | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| bool select; | bool select; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const char *active_uv_name = CustomData_get_active_layer_name(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| BM_uv_map_ensure_vert_select_attr(em->bm, active_uv_name); | |||||
| BM_uv_map_ensure_edge_select_attr(em->bm, active_uv_name); | |||||
| const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | |||||
| if (!extend) { | if (!extend) { | ||||
| uv_select_all_perform(scene, obedit, SEL_DESELECT); | uv_select_all_perform(scene, obedit, SEL_DESELECT); | ||||
| } | } | ||||
| BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); | BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); | ||||
| if (extend) { | if (extend) { | ||||
| select = !uvedit_face_select_test(scene, hit->l->f, cd_loop_uv_offset); | select = !uvedit_face_select_test(scene, hit->l->f, offsets); | ||||
| } | } | ||||
| else { | else { | ||||
| select = true; | select = true; | ||||
| } | } | ||||
| BMLoop *l_pair[2] = { | BMLoop *l_pair[2] = { | ||||
| hit->l, | hit->l, | ||||
| uvedit_loop_find_other_radial_loop_with_visible_face(scene, hit->l, cd_loop_uv_offset), | uvedit_loop_find_other_radial_loop_with_visible_face(scene, hit->l, offsets), | ||||
| }; | }; | ||||
| for (int side = 0; side < 2; side++) { | for (int side = 0; side < 2; side++) { | ||||
| BMLoop *l_step = l_pair[side]; | BMLoop *l_step = l_pair[side]; | ||||
| while (l_step) { | while (l_step) { | ||||
| if (!uvedit_face_visible_test(scene, l_step->f)) { | if (!uvedit_face_visible_test(scene, l_step->f)) { | ||||
| break; | break; | ||||
| } | } | ||||
| uvedit_face_select_set_with_sticky(scene, em, l_step->f, select, false, cd_loop_uv_offset); | uvedit_face_select_set_with_sticky(scene, em, l_step->f, select, false, offsets); | ||||
| BM_elem_flag_enable(l_step->f, BM_ELEM_TAG); | BM_elem_flag_enable(l_step->f, BM_ELEM_TAG); | ||||
| if (l_step->f->len == 4) { | if (l_step->f->len == 4) { | ||||
| BMLoop *l_step_opposite = l_step->next->next; | BMLoop *l_step_opposite = l_step->next->next; | ||||
| l_step = uvedit_loop_find_other_radial_loop_with_visible_face( | l_step = uvedit_loop_find_other_radial_loop_with_visible_face( | ||||
| scene, l_step_opposite, cd_loop_uv_offset); | scene, l_step_opposite, offsets); | ||||
| } | } | ||||
| else { | else { | ||||
| l_step = NULL; | l_step = NULL; | ||||
| } | } | ||||
| /* Break iteration when `l_step`: | /* Break iteration when `l_step`: | ||||
| * - is the first loop where we started from. | * - is the first loop where we started from. | ||||
| * - tagged using #BM_ELEM_TAG (meaning this loop has been visited in this iteration). */ | * - tagged using #BM_ELEM_TAG (meaning this loop has been visited in this iteration). */ | ||||
| Show All 19 Lines | static int uv_select_edgering(Scene *scene, Object *obedit, UvNearestHit *hit, const bool extend) | ||||
| const bool use_face_select = (ts->uv_flag & UV_SYNC_SELECTION) ? | const bool use_face_select = (ts->uv_flag & UV_SYNC_SELECTION) ? | ||||
| (ts->selectmode & SCE_SELECT_FACE) : | (ts->selectmode & SCE_SELECT_FACE) : | ||||
| (ts->uv_selectmode & UV_SELECT_FACE); | (ts->uv_selectmode & UV_SELECT_FACE); | ||||
| const bool use_vertex_select = (ts->uv_flag & UV_SYNC_SELECTION) ? | const bool use_vertex_select = (ts->uv_flag & UV_SYNC_SELECTION) ? | ||||
| (ts->selectmode & SCE_SELECT_VERTEX) : | (ts->selectmode & SCE_SELECT_VERTEX) : | ||||
| (ts->uv_selectmode & UV_SELECT_VERTEX); | (ts->uv_selectmode & UV_SELECT_VERTEX); | ||||
| bool select; | bool select; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const char *active_uv_name = CustomData_get_active_layer_name(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| BM_uv_map_ensure_vert_select_attr(em->bm, active_uv_name); | |||||
| BM_uv_map_ensure_edge_select_attr(em->bm, active_uv_name); | |||||
| const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | |||||
| if (!extend) { | if (!extend) { | ||||
| uv_select_all_perform(scene, obedit, SEL_DESELECT); | uv_select_all_perform(scene, obedit, SEL_DESELECT); | ||||
| } | } | ||||
| 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); | ||||
| if (extend) { | if (extend) { | ||||
| select = !uvedit_edge_select_test(scene, hit->l, cd_loop_uv_offset); | select = !uvedit_edge_select_test(scene, hit->l, offsets); | ||||
| } | } | ||||
| else { | else { | ||||
| select = true; | select = true; | ||||
| } | } | ||||
| BMLoop *l_pair[2] = { | BMLoop *l_pair[2] = { | ||||
| hit->l, | hit->l, | ||||
| uvedit_loop_find_other_radial_loop_with_visible_face(scene, hit->l, cd_loop_uv_offset), | uvedit_loop_find_other_radial_loop_with_visible_face(scene, hit->l, offsets), | ||||
| }; | }; | ||||
| for (int side = 0; side < 2; side++) { | for (int side = 0; side < 2; side++) { | ||||
| BMLoop *l_step = l_pair[side]; | BMLoop *l_step = l_pair[side]; | ||||
| /* Disable since we start from the same edge. */ | /* Disable since we start from the same edge. */ | ||||
| BM_elem_flag_disable(hit->l->e, BM_ELEM_TAG); | BM_elem_flag_disable(hit->l->e, BM_ELEM_TAG); | ||||
| while (l_step) { | while (l_step) { | ||||
| if (!uvedit_face_visible_test(scene, l_step->f)) { | if (!uvedit_face_visible_test(scene, l_step->f)) { | ||||
| break; | break; | ||||
| } | } | ||||
| if (use_face_select) { | if (use_face_select) { | ||||
| /* While selecting face loops is now done in a separate function #uv_select_faceloop(), | /* While selecting face loops is now done in a separate function #uv_select_faceloop(), | ||||
| * this check is still kept for edge ring selection, to keep it consistent with how edge | * this check is still kept for edge ring selection, to keep it consistent with how edge | ||||
| * ring selection works in face mode in the 3D viewport. */ | * ring selection works in face mode in the 3D viewport. */ | ||||
| uvedit_face_select_set_with_sticky(scene, em, l_step->f, select, false, cd_loop_uv_offset); | uvedit_face_select_set_with_sticky(scene, em, l_step->f, select, false, offsets); | ||||
| } | } | ||||
| else if (use_vertex_select) { | else if (use_vertex_select) { | ||||
| uvedit_uv_select_set_with_sticky(scene, em, l_step, select, false, cd_loop_uv_offset); | uvedit_uv_select_set_with_sticky(scene, em, l_step, select, false, offsets); | ||||
| uvedit_uv_select_set_with_sticky( | uvedit_uv_select_set_with_sticky(scene, em, l_step->next, select, false, offsets); | ||||
| scene, em, l_step->next, select, false, cd_loop_uv_offset); | |||||
| } | } | ||||
| else { | else { | ||||
| /* Edge select mode */ | /* Edge select mode */ | ||||
| uvedit_edge_select_set_with_sticky(scene, em, l_step, select, false, cd_loop_uv_offset); | uvedit_edge_select_set_with_sticky(scene, em, l_step, select, false, offsets); | ||||
| } | } | ||||
| BM_elem_flag_enable(l_step->e, BM_ELEM_TAG); | BM_elem_flag_enable(l_step->e, BM_ELEM_TAG); | ||||
| if (l_step->f->len == 4) { | if (l_step->f->len == 4) { | ||||
| BMLoop *l_step_opposite = l_step->next->next; | BMLoop *l_step_opposite = l_step->next->next; | ||||
| l_step = uvedit_loop_find_other_radial_loop_with_visible_face( | l_step = uvedit_loop_find_other_radial_loop_with_visible_face( | ||||
| scene, l_step_opposite, cd_loop_uv_offset); | scene, l_step_opposite, offsets); | ||||
| if (l_step == NULL) { | if (l_step == NULL) { | ||||
| /* Ensure we touch the opposite edge if we can't walk over it. */ | /* Ensure we touch the opposite edge if we can't walk over it. */ | ||||
| l_step = l_step_opposite; | l_step = l_step_opposite; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| l_step = NULL; | l_step = NULL; | ||||
| } | } | ||||
| /* Break iteration when `l_step`: | /* Break iteration when `l_step`: | ||||
| * - Is the first loop where we started from. | * - Is the first loop where we started from. | ||||
| * - Tagged using #BM_ELEM_TAG (meaning this loop has been visited in this iteration). | * - Tagged using #BM_ELEM_TAG (meaning this loop has been visited in this iteration). | ||||
| * - Has its corresponding UV edge selected/unselected based on #select. */ | * - Has its corresponding UV edge selected/unselected based on #select. */ | ||||
| if (l_step && BM_elem_flag_test(l_step->e, BM_ELEM_TAG)) { | if (l_step && BM_elem_flag_test(l_step->e, BM_ELEM_TAG)) { | ||||
| /* Previously this check was not done and this resulted in the final edge in the edge ring | /* Previously this check was not done and this resulted in the final edge in the edge ring | ||||
| * cycle to be skipped during selection (caused by old sticky selection behavior). */ | * cycle to be skipped during selection (caused by old sticky selection behavior). */ | ||||
| if (select && uvedit_edge_select_test(scene, l_step, cd_loop_uv_offset)) { | if (select && uvedit_edge_select_test(scene, l_step, offsets)) { | ||||
| break; | break; | ||||
| } | } | ||||
| if (!select && !uvedit_edge_select_test(scene, l_step, cd_loop_uv_offset)) { | if (!select && !uvedit_edge_select_test(scene, l_step, offsets)) { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return (select) ? 1 : -1; | return (select) ? 1 : -1; | ||||
| } | } | ||||
| Show All 27 Lines | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| UvVertMap *vmap; | UvVertMap *vmap; | ||||
| UvMapVert *vlist, *iterv, *startv; | UvMapVert *vlist, *iterv, *startv; | ||||
| int i, stacksize = 0, *stack; | int i, stacksize = 0, *stack; | ||||
| uint a; | uint a; | ||||
| char *flag; | char *flag; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const char *active_uv_name = CustomData_get_active_layer_name(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| BLI_assert(active_uv_name != NULL); | |||||
| BM_uv_map_ensure_vert_select_attr(em->bm, active_uv_name); | |||||
| BM_uv_map_ensure_edge_select_attr(em->bm, active_uv_name); | |||||
| const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | |||||
| BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */ | BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */ | ||||
| /* NOTE: we had 'use winding' so we don't consider overlapping islands as connected, see T44320 | /* NOTE: we had 'use winding' so we don't consider overlapping islands as connected, see T44320 | ||||
| * this made *every* projection split the island into front/back islands. | * this made *every* projection split the island into front/back islands. | ||||
| * Keep 'use_winding' to false, see: T50970. | * Keep 'use_winding' to false, see: T50970. | ||||
| * | * | ||||
| * Better solve this by having a delimit option for select-linked operator, | * Better solve this by having a delimit option for select-linked operator, | ||||
| Show All 15 Lines | if (hit == NULL) { | ||||
| if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { | if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { | ||||
| stack[stacksize] = a; | stack[stacksize] = a; | ||||
| stacksize++; | stacksize++; | ||||
| flag[a] = 1; | flag[a] = 1; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { | if (uvedit_uv_select_test(scene, l, offsets)) { | ||||
| bool add_to_stack = true; | bool add_to_stack = true; | ||||
| if (uv_sync_select) { | if (uv_sync_select) { | ||||
| /* Special case, vertex/edge & sync select being enabled. | /* Special case, vertex/edge & sync select being enabled. | ||||
| * | * | ||||
| * Without this, a second linked select will 'grow' each time as each new | * Without this, a second linked select will 'grow' each time as each new | ||||
| * selection reaches the boundaries of islands that share vertices but not UV's. | * selection reaches the boundaries of islands that share vertices but not UV's. | ||||
| * | * | ||||
| * Rules applied here: | * Rules applied here: | ||||
| * - This loops face isn't selected. | * - This loops face isn't selected. | ||||
| * - The only other fully selected face is connected or, | * - The only other fully selected face is connected or, | ||||
| * - There are no connected fully selected faces UV-connected to this loop. | * - There are no connected fully selected faces UV-connected to this loop. | ||||
| */ | */ | ||||
| BLI_assert(!select_faces); | BLI_assert(!select_faces); | ||||
| if (uvedit_face_select_test(scene, l->f, cd_loop_uv_offset)) { | if (uvedit_face_select_test(scene, l->f, offsets)) { | ||||
| /* pass */ | /* pass */ | ||||
| } | } | ||||
| else { | else { | ||||
| BMIter liter_other; | BMIter liter_other; | ||||
| BMLoop *l_other; | BMLoop *l_other; | ||||
| BM_ITER_ELEM (l_other, &liter_other, l->v, BM_LOOPS_OF_VERT) { | BM_ITER_ELEM (l_other, &liter_other, l->v, BM_LOOPS_OF_VERT) { | ||||
| if ((l != l_other) && | if ((l != l_other) && !BM_loop_uv_share_vert_check(l, l_other, offsets.uv) && | ||||
| !BM_loop_uv_share_vert_check(l, l_other, cd_loop_uv_offset) && | uvedit_face_select_test(scene, l_other->f, offsets)) { | ||||
| uvedit_face_select_test(scene, l_other->f, cd_loop_uv_offset)) { | |||||
| add_to_stack = false; | add_to_stack = false; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (add_to_stack) { | if (add_to_stack) { | ||||
| ▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | if ((toggle == true) && (extend == false) && (deselect == false)) { | ||||
| if (select_faces) { | if (select_faces) { | ||||
| if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { | if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { | ||||
| found_selected = true; | found_selected = true; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { | if (uvedit_uv_select_test(scene, l, offsets)) { | ||||
| found_selected = true; | found_selected = true; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| if (found_selected) { | if (found_selected) { | ||||
| deselect = true; | deselect = true; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| #define SET_SELECTION(value) \ | #define SET_SELECTION(value) \ | ||||
| if (select_faces) { \ | if (select_faces) { \ | ||||
| BM_face_select_set(em->bm, efa, value); \ | BM_face_select_set(em->bm, efa, value); \ | ||||
| } \ | } \ | ||||
| else { \ | else { \ | ||||
| uvedit_face_select_set(scene, em->bm, efa, value, false, cd_loop_uv_offset); \ | uvedit_face_select_set(scene, em->bm, efa, value, false, offsets); \ | ||||
| } \ | } \ | ||||
| (void)0 | (void)0 | ||||
| BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { | BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { | ||||
| if (!flag[a]) { | if (!flag[a]) { | ||||
| if (!extend && !deselect && !toggle) { | if (!extend && !deselect && !toggle) { | ||||
| SET_SELECTION(false); | SET_SELECTION(false); | ||||
| } | } | ||||
| Show All 24 Lines | if (uv_sync_select) { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| const float *uvedit_first_selected_uv_from_vertex(Scene *scene, | const float *uvedit_first_selected_uv_from_vertex(Scene *scene, | ||||
| BMVert *eve, | BMVert *eve, | ||||
| const int cd_loop_uv_offset) | const BMUVOffsets offsets) | ||||
| { | { | ||||
| BMIter liter; | BMIter liter; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) { | BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) { | ||||
| if (!uvedit_face_visible_test(scene, l->f)) { | if (!uvedit_face_visible_test(scene, l->f)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { | if (uvedit_uv_select_test(scene, l, offsets)) { | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | float *luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv); | ||||
| return luv->uv; | return luv; | ||||
| } | } | ||||
| } | } | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| Show All 18 Lines | static int uv_select_more_less(bContext *C, const bool select) | ||||
| const bool is_uv_face_selectmode = (ts->uv_selectmode == UV_SELECT_FACE); | const bool is_uv_face_selectmode = (ts->uv_selectmode == UV_SELECT_FACE); | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| Object *obedit = objects[ob_index]; | Object *obedit = objects[ob_index]; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| bool changed = false; | bool changed = false; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const char *active_uv_name = CustomData_get_active_layer_name(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| BM_uv_map_ensure_vert_select_attr(em->bm, active_uv_name); | |||||
| BM_uv_map_ensure_edge_select_attr(em->bm, active_uv_name); | |||||
| const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | |||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | if (ts->uv_flag & UV_SYNC_SELECTION) { | ||||
| if (select) { | if (select) { | ||||
| EDBM_select_more(em, true); | EDBM_select_more(em, true); | ||||
| } | } | ||||
| else { | else { | ||||
| EDBM_select_less(em, true); | EDBM_select_less(em, true); | ||||
| } | } | ||||
| Show All 14 Lines | if (is_uv_face_selectmode) { | ||||
| if (select) { | if (select) { | ||||
| #define NEIGHBORING_FACE_IS_SEL 1 | #define NEIGHBORING_FACE_IS_SEL 1 | ||||
| #define CURR_FACE_IS_UNSEL 2 | #define CURR_FACE_IS_UNSEL 2 | ||||
| int sel_state = 0; | int sel_state = 0; | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | if (BM_ELEM_CD_GET_BOOL(l, offsets.select_vert)) { | ||||
| if (luv->flag & MLOOPUV_VERTSEL) { | |||||
| sel_state |= NEIGHBORING_FACE_IS_SEL; | sel_state |= NEIGHBORING_FACE_IS_SEL; | ||||
| } | } | ||||
| else { | else { | ||||
| sel_state |= CURR_FACE_IS_UNSEL; | sel_state |= CURR_FACE_IS_UNSEL; | ||||
| } | } | ||||
| if (!(luv->flag & MLOOPUV_EDGESEL)) { | if (!BM_ELEM_CD_GET_BOOL(l, offsets.select_edge)) { | ||||
| sel_state |= CURR_FACE_IS_UNSEL; | sel_state |= CURR_FACE_IS_UNSEL; | ||||
| } | } | ||||
| /* If the current face is not selected and at least one neighboring face is | /* If the current face is not selected and at least one neighboring face is | ||||
| * selected, then tag the current face to grow selection. */ | * selected, then tag the current face to grow selection. */ | ||||
| if (sel_state == (NEIGHBORING_FACE_IS_SEL | CURR_FACE_IS_UNSEL)) { | if (sel_state == (NEIGHBORING_FACE_IS_SEL | CURR_FACE_IS_UNSEL)) { | ||||
| BM_elem_flag_enable(efa, BM_ELEM_TAG); | BM_elem_flag_enable(efa, BM_ELEM_TAG); | ||||
| changed = true; | changed = true; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| #undef NEIGHBORING_FACE_IS_SEL | #undef NEIGHBORING_FACE_IS_SEL | ||||
| #undef CURR_FACE_IS_UNSEL | #undef CURR_FACE_IS_UNSEL | ||||
| } | } | ||||
| else { | else { | ||||
| if (!uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { | if (!uvedit_face_select_test(scene, efa, offsets)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| /* Deselect face when at least one of the surrounding faces is not selected */ | /* Deselect face when at least one of the surrounding faces is not selected */ | ||||
| if (!uvedit_vert_is_all_other_faces_selected(scene, l, cd_loop_uv_offset)) { | if (!uvedit_vert_is_all_other_faces_selected(scene, l, offsets)) { | ||||
| BM_elem_flag_enable(efa, BM_ELEM_TAG); | BM_elem_flag_enable(efa, BM_ELEM_TAG); | ||||
| changed = true; | changed = true; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* clear tags */ | /* clear tags */ | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| BM_elem_flag_disable(l, BM_ELEM_TAG); | BM_elem_flag_disable(l, BM_ELEM_TAG); | ||||
| } | } | ||||
| } | } | ||||
| /* mark loops to be selected */ | /* mark loops to be selected */ | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (uvedit_face_visible_test(scene, efa)) { | if (uvedit_face_visible_test(scene, efa)) { | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | if (BM_ELEM_CD_GET_BOOL(l, offsets.select_vert) == select) { | ||||
| if (((luv->flag & MLOOPUV_VERTSEL) != 0) == select) { | |||||
| BM_elem_flag_enable(l->next, BM_ELEM_TAG); | BM_elem_flag_enable(l->next, BM_ELEM_TAG); | ||||
| BM_elem_flag_enable(l->prev, BM_ELEM_TAG); | BM_elem_flag_enable(l->prev, BM_ELEM_TAG); | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | |||||
| bool uvedit_select_is_any_selected(const Scene *scene, Object *obedit) | bool uvedit_select_is_any_selected(const Scene *scene, Object *obedit) | ||||
| { | { | ||||
| const ToolSettings *ts = scene->toolsettings; | const ToolSettings *ts = scene->toolsettings; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| MLoopUV *luv; | |||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | if (ts->uv_flag & UV_SYNC_SELECTION) { | ||||
| return (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel); | return (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel); | ||||
| } | } | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | if (BM_ELEM_CD_GET_BOOL(l, offsets.select_vert)) { | ||||
| if (luv->flag & MLOOPUV_VERTSEL) { | |||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| bool uvedit_select_is_any_selected_multi(const Scene *scene, | bool uvedit_select_is_any_selected_multi(const Scene *scene, | ||||
| Show All 11 Lines | bool uvedit_select_is_any_selected_multi(const Scene *scene, | ||||
| return found; | return found; | ||||
| } | } | ||||
| static void uv_select_all(const Scene *scene, BMEditMesh *em, bool select_all) | static void uv_select_all(const Scene *scene, BMEditMesh *em, bool select_all) | ||||
| { | { | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| MLoopUV *luv; | const char *active_uv_name = CustomData_get_active_layer_name(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | BM_uv_map_ensure_vert_select_attr(em->bm, active_uv_name); | ||||
| const int uv_select_flags = (MLOOPUV_VERTSEL | MLOOPUV_EDGESEL); | BM_uv_map_ensure_edge_select_attr(em->bm, active_uv_name); | ||||
| const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | |||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | BM_ELEM_CD_SET_BOOL(l, offsets.select_vert, select_all); | ||||
| SET_FLAG_FROM_TEST(luv->flag, select_all, uv_select_flags); | BM_ELEM_CD_SET_BOOL(l, offsets.select_edge, select_all); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void uv_select_invert(const Scene *scene, BMEditMesh *em) | static void uv_select_invert(const Scene *scene, BMEditMesh *em) | ||||
| { | { | ||||
| const ToolSettings *ts = scene->toolsettings; | const ToolSettings *ts = scene->toolsettings; | ||||
| BLI_assert((ts->uv_flag & UV_SYNC_SELECTION) == 0); | BLI_assert((ts->uv_flag & UV_SYNC_SELECTION) == 0); | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const char *active_uv_name = CustomData_get_active_layer_name(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| BM_uv_map_ensure_vert_select_attr(em->bm, active_uv_name); | |||||
| BM_uv_map_ensure_edge_select_attr(em->bm, active_uv_name); | |||||
| const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | |||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| MLoopUV *luv; | |||||
| char uv_selectmode = ts->uv_selectmode; | char uv_selectmode = ts->uv_selectmode; | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | if ((uv_selectmode == UV_SELECT_EDGE) || (uv_selectmode == UV_SELECT_FACE)) { | ||||
| if (ELEM(uv_selectmode, UV_SELECT_EDGE, UV_SELECT_FACE)) { | /* Use UV edge selection to find vertices and edges that must be selected. */ | ||||
| /* Use #MLOOPUV_EDGESEL to flag edges that must be selected. */ | bool es = BM_ELEM_CD_GET_BOOL(l, offsets.select_edge); | ||||
| luv->flag ^= MLOOPUV_EDGESEL; | BM_ELEM_CD_SET_BOOL(l, offsets.select_edge, !es); | ||||
| luv->flag &= ~MLOOPUV_VERTSEL; | BM_ELEM_CD_SET_BOOL(l, offsets.select_vert, false); | ||||
| } | } | ||||
| /* Use #MLOOPUV_VERTSEL to flag verts that must be selected. */ | /* Use UV vertex selection to find vertices and edges that must be selected. */ | ||||
| else if (ELEM(uv_selectmode, UV_SELECT_VERTEX, UV_SELECT_ISLAND)) { | else if ((uv_selectmode == UV_SELECT_VERTEX) || (uv_selectmode == UV_SELECT_ISLAND)) { | ||||
| luv->flag ^= MLOOPUV_VERTSEL; | bool vs = BM_ELEM_CD_GET_BOOL(l, offsets.select_vert); | ||||
| luv->flag &= ~MLOOPUV_EDGESEL; | BM_ELEM_CD_SET_BOOL(l, offsets.select_vert, !vs); | ||||
| BM_ELEM_CD_SET_BOOL(l, offsets.select_edge, false); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Flush based on uv vert/edge flags and current UV select mode */ | /* Flush based on uv vert/edge flags and current UV select mode */ | ||||
| if (ELEM(uv_selectmode, UV_SELECT_EDGE, UV_SELECT_FACE)) { | if (ELEM(uv_selectmode, UV_SELECT_EDGE, UV_SELECT_FACE)) { | ||||
| uv_select_flush_from_loop_edge_flag(scene, em); | uv_select_flush_from_loop_edge_flag(scene, em); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 207 Lines • ▼ Show 20 Lines | static bool uv_mouse_select_multi(bContext *C, | ||||
| bool found = found_item; | bool found = found_item; | ||||
| bool changed = false; | bool changed = false; | ||||
| bool is_selected = false; | bool is_selected = false; | ||||
| if (found) { | if (found) { | ||||
| Object *obedit = hit.ob; | Object *obedit = hit.ob; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const char *active_uv_name = CustomData_get_active_layer_name(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| BM_uv_map_ensure_vert_select_attr(em->bm, active_uv_name); | |||||
| BM_uv_map_ensure_edge_select_attr(em->bm, active_uv_name); | |||||
| const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | |||||
| if (selectmode == UV_SELECT_FACE) { | if (selectmode == UV_SELECT_FACE) { | ||||
| is_selected = uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset); | is_selected = uvedit_face_select_test(scene, hit.efa, offsets); | ||||
| } | } | ||||
| else if (selectmode == UV_SELECT_EDGE) { | else if (selectmode == UV_SELECT_EDGE) { | ||||
| is_selected = uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset); | is_selected = uvedit_edge_select_test(scene, hit.l, offsets); | ||||
| } | } | ||||
| else { | else { | ||||
| /* Vertex or island. For island (if we were using #uv_find_nearest_face_multi_ex, see above), | /* Vertex or island. For island (if we were using #uv_find_nearest_face_multi_ex, see above), | ||||
| * `hit.l` is NULL, use `hit.efa` instead. */ | * `hit.l` is NULL, use `hit.efa` instead. */ | ||||
| if (hit.l != NULL) { | if (hit.l != NULL) { | ||||
| is_selected = uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset); | is_selected = uvedit_uv_select_test(scene, hit.l, offsets); | ||||
| } | } | ||||
| else { | else { | ||||
| is_selected = uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset); | is_selected = uvedit_face_select_test(scene, hit.efa, offsets); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (params->sel_op == SEL_OP_SET) { | if (params->sel_op == SEL_OP_SET) { | ||||
| if ((found && params->select_passthrough) && is_selected) { | if ((found && params->select_passthrough) && is_selected) { | ||||
| found = false; | found = false; | ||||
| } | } | ||||
| else if (found || params->deselect_all) { | else if (found || params->deselect_all) { | ||||
| /* Deselect everything. */ | /* Deselect everything. */ | ||||
| uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); | uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| Object *obedit = objects[ob_index]; | Object *obedit = objects[ob_index]; | ||||
| uv_select_tag_update_for_object(depsgraph, ts, obedit); | uv_select_tag_update_for_object(depsgraph, ts, obedit); | ||||
| } | } | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| if (found) { | if (found) { | ||||
| Object *obedit = hit.ob; | Object *obedit = hit.ob; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const char *active_uv_name = CustomData_get_active_layer_name(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| BM_uv_map_ensure_vert_select_attr(em->bm, active_uv_name); | |||||
| BM_uv_map_ensure_edge_select_attr(em->bm, active_uv_name); | |||||
| const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | |||||
| if (selectmode == UV_SELECT_ISLAND) { | if (selectmode == UV_SELECT_ISLAND) { | ||||
| const bool extend = params->sel_op == SEL_OP_ADD; | const bool extend = params->sel_op == SEL_OP_ADD; | ||||
| const bool deselect = params->sel_op == SEL_OP_SUB; | const bool deselect = params->sel_op == SEL_OP_SUB; | ||||
| const bool toggle = params->sel_op == SEL_OP_XOR; | const bool toggle = params->sel_op == SEL_OP_XOR; | ||||
| /* Current behavior of 'extend' | /* Current behavior of 'extend' | ||||
| * is actually toggling, so pass extend flag as 'toggle' here */ | * is actually toggling, so pass extend flag as 'toggle' here */ | ||||
| uv_select_linked_multi(scene, objects, objects_len, &hit, extend, deselect, toggle, false); | uv_select_linked_multi(scene, objects, objects_len, &hit, extend, deselect, toggle, false); | ||||
| Show All 23 Lines | else { | ||||
| } | } | ||||
| case SEL_OP_AND: { | case SEL_OP_AND: { | ||||
| BLI_assert_unreachable(); /* Doesn't make sense for picking. */ | BLI_assert_unreachable(); /* Doesn't make sense for picking. */ | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| if (selectmode == UV_SELECT_FACE) { | if (selectmode == UV_SELECT_FACE) { | ||||
| uvedit_face_select_set_with_sticky( | uvedit_face_select_set_with_sticky(scene, em, hit.efa, select_value, true, offsets); | ||||
| scene, em, hit.efa, select_value, true, cd_loop_uv_offset); | |||||
| flush = 1; | flush = 1; | ||||
| } | } | ||||
| else if (selectmode == UV_SELECT_EDGE) { | else if (selectmode == UV_SELECT_EDGE) { | ||||
| uvedit_edge_select_set_with_sticky( | uvedit_edge_select_set_with_sticky(scene, em, hit.l, select_value, true, offsets); | ||||
| scene, em, hit.l, select_value, true, cd_loop_uv_offset); | |||||
| flush = 1; | flush = 1; | ||||
| } | } | ||||
| else if (selectmode == UV_SELECT_VERTEX) { | else if (selectmode == UV_SELECT_VERTEX) { | ||||
| uvedit_uv_select_set_with_sticky(scene, em, hit.l, select_value, true, cd_loop_uv_offset); | uvedit_uv_select_set_with_sticky(scene, em, hit.l, select_value, true, offsets); | ||||
| flush = 1; | flush = 1; | ||||
| } | } | ||||
| else { | else { | ||||
| BLI_assert_unreachable(); | BLI_assert_unreachable(); | ||||
| } | } | ||||
| /* De-selecting an edge may deselect a face too - validate. */ | /* De-selecting an edge may deselect a face too - validate. */ | ||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | if (ts->uv_flag & UV_SYNC_SELECTION) { | ||||
| ▲ Show 20 Lines • Show All 489 Lines • ▼ Show 20 Lines | static int uv_select_split_exec(bContext *C, wmOperator *op) | ||||
| Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); | Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); | ||||
| Scene *scene = CTX_data_scene(C); | Scene *scene = CTX_data_scene(C); | ||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| const ToolSettings *ts = scene->toolsettings; | const ToolSettings *ts = scene->toolsettings; | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| MLoopUV *luv; | |||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | if (ts->uv_flag & UV_SYNC_SELECTION) { | ||||
| BKE_report(op->reports, RPT_ERROR, "Cannot split selection when sync selection is enabled"); | BKE_report(op->reports, RPT_ERROR, "Cannot split selection when sync selection is enabled"); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| bool changed_multi = false; | bool changed_multi = false; | ||||
| uint objects_len = 0; | uint objects_len = 0; | ||||
| Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( | Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( | ||||
| scene, view_layer, ((View3D *)NULL), &objects_len); | scene, view_layer, ((View3D *)NULL), &objects_len); | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| Object *obedit = objects[ob_index]; | Object *obedit = objects[ob_index]; | ||||
| BMesh *bm = BKE_editmesh_from_object(obedit)->bm; | BMesh *bm = BKE_editmesh_from_object(obedit)->bm; | ||||
| bool changed = false; | bool changed = false; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); | const char *active_uv_name = CustomData_get_active_layer_name(&bm->ldata, CD_PROP_FLOAT2); | ||||
| BM_uv_map_ensure_vert_select_attr(bm, active_uv_name); | |||||
| BM_uv_map_ensure_edge_select_attr(bm, active_uv_name); | |||||
| const BMUVOffsets offsets = BM_uv_map_get_offsets(bm); | |||||
| BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { | ||||
| bool is_sel = false; | bool is_sel = false; | ||||
| bool is_unsel = false; | bool is_unsel = false; | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* are we all selected? */ | /* are we all selected? */ | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | |||||
| if ((luv->flag & MLOOPUV_VERTSEL) || (luv->flag & MLOOPUV_EDGESEL)) { | if (BM_ELEM_CD_GET_BOOL(l, offsets.select_vert) || | ||||
| BM_ELEM_CD_GET_BOOL(l, offsets.select_edge)) { | |||||
| is_sel = true; | is_sel = true; | ||||
| } | } | ||||
| if (!(luv->flag & MLOOPUV_VERTSEL) || !(luv->flag & MLOOPUV_EDGESEL)) { | if (!BM_ELEM_CD_GET_BOOL(l, offsets.select_vert) || | ||||
| !BM_ELEM_CD_GET_BOOL(l, offsets.select_edge)) { | |||||
| is_unsel = true; | is_unsel = true; | ||||
| } | } | ||||
| /* we have mixed selection, bail out */ | /* we have mixed selection, bail out */ | ||||
| if (is_sel && is_unsel) { | if (is_sel && is_unsel) { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| if (is_sel && is_unsel) { | if (is_sel && is_unsel) { | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | BM_ELEM_CD_SET_BOOL(l, offsets.select_vert, false); | ||||
| luv->flag &= ~(MLOOPUV_VERTSEL | MLOOPUV_EDGESEL); | BM_ELEM_CD_SET_BOOL(l, offsets.select_edge, false); | ||||
| } | } | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| if (changed) { | if (changed) { | ||||
| changed_multi = true; | changed_multi = true; | ||||
| ▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | |||||
| * helper function for #uv_select_flush_from_tag_loop and uv_select_flush_from_tag_face | * helper function for #uv_select_flush_from_tag_loop and uv_select_flush_from_tag_face | ||||
| */ | */ | ||||
| static void uv_select_flush_from_tag_sticky_loc_internal(const Scene *scene, | static void uv_select_flush_from_tag_sticky_loc_internal(const Scene *scene, | ||||
| BMEditMesh *em, | BMEditMesh *em, | ||||
| UvVertMap *vmap, | UvVertMap *vmap, | ||||
| const uint efa_index, | const uint efa_index, | ||||
| BMLoop *l, | BMLoop *l, | ||||
| const bool select, | const bool select, | ||||
| const int cd_loop_uv_offset) | const BMUVOffsets offsets) | ||||
| { | { | ||||
| UvMapVert *start_vlist = NULL, *vlist_iter; | UvMapVert *start_vlist = NULL, *vlist_iter; | ||||
| BMFace *efa_vlist; | BMFace *efa_vlist; | ||||
| uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); | uvedit_uv_select_set(scene, em->bm, l, select, false, offsets); | ||||
| vlist_iter = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v)); | vlist_iter = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v)); | ||||
| while (vlist_iter) { | while (vlist_iter) { | ||||
| if (vlist_iter->separate) { | if (vlist_iter->separate) { | ||||
| start_vlist = vlist_iter; | start_vlist = vlist_iter; | ||||
| } | } | ||||
| Show All 13 Lines | while (vlist_iter) { | ||||
| if (efa_index != vlist_iter->poly_index) { | if (efa_index != vlist_iter->poly_index) { | ||||
| BMLoop *l_other; | BMLoop *l_other; | ||||
| efa_vlist = BM_face_at_index(em->bm, vlist_iter->poly_index); | efa_vlist = BM_face_at_index(em->bm, vlist_iter->poly_index); | ||||
| /* tf_vlist = BM_ELEM_CD_GET_VOID_P(efa_vlist, cd_poly_tex_offset); */ /* UNUSED */ | /* tf_vlist = BM_ELEM_CD_GET_VOID_P(efa_vlist, cd_poly_tex_offset); */ /* UNUSED */ | ||||
| l_other = BM_iter_at_index( | l_other = BM_iter_at_index( | ||||
| em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->loop_of_poly_index); | em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->loop_of_poly_index); | ||||
| uvedit_uv_select_set(scene, em->bm, l_other, select, false, cd_loop_uv_offset); | uvedit_uv_select_set(scene, em->bm, l_other, select, false, offsets); | ||||
| } | } | ||||
| vlist_iter = vlist_iter->next; | vlist_iter = vlist_iter->next; | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Flush the selection from face tags based on sticky and selection modes. | * Flush the selection from face tags based on sticky and selection modes. | ||||
| * | * | ||||
| Show All 12 Lines | static void uv_select_flush_from_tag_face(const Scene *scene, Object *obedit, const bool select) | ||||
| * This only needs to be done when the Mesh is not used for | * This only needs to be done when the Mesh is not used for | ||||
| * selection (so for sticky modes, vertex or location based). */ | * selection (so for sticky modes, vertex or location based). */ | ||||
| const ToolSettings *ts = scene->toolsettings; | const ToolSettings *ts = scene->toolsettings; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const char *active_uv_name = CustomData_get_active_layer_name(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| BM_uv_map_ensure_vert_select_attr(em->bm, active_uv_name); | |||||
| BM_uv_map_ensure_edge_select_attr(em->bm, active_uv_name); | |||||
| const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | |||||
| if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && | if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && | ||||
| ELEM(ts->uv_sticky, SI_STICKY_VERTEX, SI_STICKY_LOC)) { | ELEM(ts->uv_sticky, SI_STICKY_VERTEX, SI_STICKY_LOC)) { | ||||
| struct UvVertMap *vmap; | struct UvVertMap *vmap; | ||||
| uint efa_index; | uint efa_index; | ||||
| BM_mesh_elem_table_ensure(em->bm, BM_FACE); | BM_mesh_elem_table_ensure(em->bm, BM_FACE); | ||||
| vmap = BM_uv_vert_map_create(em->bm, false, false); | vmap = BM_uv_vert_map_create(em->bm, false, false); | ||||
| if (vmap == NULL) { | if (vmap == NULL) { | ||||
| return; | return; | ||||
| } | } | ||||
| BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) { | BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) { | ||||
| if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { | if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | |||||
| if (select) { | if (select) { | ||||
| luv->flag |= MLOOPUV_EDGESEL; | BM_ELEM_CD_SET_BOOL(l, offsets.select_vert, true); | ||||
| uv_select_flush_from_tag_sticky_loc_internal( | uv_select_flush_from_tag_sticky_loc_internal( | ||||
| scene, em, vmap, efa_index, l, select, cd_loop_uv_offset); | scene, em, vmap, efa_index, l, select, offsets); | ||||
| } | } | ||||
| else { | else { | ||||
| luv->flag &= ~MLOOPUV_EDGESEL; | BM_ELEM_CD_SET_BOOL(l, offsets.select_vert, false); | ||||
| if (!uvedit_vert_is_face_select_any_other(scene, l, cd_loop_uv_offset)) { | if (!uvedit_vert_is_face_select_any_other(scene, l, offsets)) { | ||||
| uv_select_flush_from_tag_sticky_loc_internal( | uv_select_flush_from_tag_sticky_loc_internal( | ||||
| scene, em, vmap, efa_index, l, select, cd_loop_uv_offset); | scene, em, vmap, efa_index, l, select, offsets); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| BM_uv_vert_map_free(vmap); | BM_uv_vert_map_free(vmap); | ||||
| } | } | ||||
| else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */ | else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */ | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { | if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { | ||||
| uvedit_face_select_set(scene, em->bm, efa, select, false, cd_loop_uv_offset); | uvedit_face_select_set(scene, em->bm, efa, select, false, offsets); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Flush the selection from loop tags based on sticky and selection modes. | * Flush the selection from loop tags based on sticky and selection modes. | ||||
| * | * | ||||
| Show All 13 Lines | static void uv_select_flush_from_tag_loop(const Scene *scene, Object *obedit, const bool select) | ||||
| * selection (so for sticky modes, vertex or location based). */ | * selection (so for sticky modes, vertex or location based). */ | ||||
| const ToolSettings *ts = scene->toolsettings; | const ToolSettings *ts = scene->toolsettings; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const char *active_uv_name = CustomData_get_active_layer_name(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| BM_uv_map_ensure_vert_select_attr(em->bm, active_uv_name); | |||||
| BM_uv_map_ensure_edge_select_attr(em->bm, active_uv_name); | |||||
| const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | |||||
| if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && ts->uv_sticky == SI_STICKY_VERTEX) { | if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && ts->uv_sticky == SI_STICKY_VERTEX) { | ||||
| /* Tag all verts as untouched, then touch the ones that have a face center | /* Tag all verts as untouched, then touch the ones that have a face center | ||||
| * in the loop and select all MLoopUV's that use a touched vert. */ | * in the loop and select all UV's that use a touched vert. */ | ||||
| BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); | BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| if (BM_elem_flag_test(l, BM_ELEM_TAG)) { | if (BM_elem_flag_test(l, BM_ELEM_TAG)) { | ||||
| BM_elem_flag_enable(l->v, BM_ELEM_TAG); | BM_elem_flag_enable(l->v, BM_ELEM_TAG); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* now select tagged verts */ | /* now select tagged verts */ | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { | if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { | ||||
| uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); | uvedit_uv_select_set(scene, em->bm, l, select, false, offsets); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && ts->uv_sticky == SI_STICKY_LOC) { | else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && ts->uv_sticky == SI_STICKY_LOC) { | ||||
| struct UvVertMap *vmap; | struct UvVertMap *vmap; | ||||
| uint efa_index; | uint efa_index; | ||||
| BM_mesh_elem_table_ensure(em->bm, BM_FACE); | BM_mesh_elem_table_ensure(em->bm, BM_FACE); | ||||
| vmap = BM_uv_vert_map_create(em->bm, false, false); | vmap = BM_uv_vert_map_create(em->bm, false, false); | ||||
| if (vmap == NULL) { | if (vmap == NULL) { | ||||
| return; | return; | ||||
| } | } | ||||
| BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) { | BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) { | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| if (BM_elem_flag_test(l, BM_ELEM_TAG)) { | if (BM_elem_flag_test(l, BM_ELEM_TAG)) { | ||||
| uv_select_flush_from_tag_sticky_loc_internal( | uv_select_flush_from_tag_sticky_loc_internal( | ||||
| scene, em, vmap, efa_index, l, select, cd_loop_uv_offset); | scene, em, vmap, efa_index, l, select, offsets); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| BM_uv_vert_map_free(vmap); | BM_uv_vert_map_free(vmap); | ||||
| } | } | ||||
| else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */ | else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */ | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| if (BM_elem_flag_test(l, BM_ELEM_TAG)) { | if (BM_elem_flag_test(l, BM_ELEM_TAG)) { | ||||
| uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); | uvedit_uv_select_set(scene, em->bm, l, select, false, offsets); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Flush the selection from UV edge flags based on sticky modes. | * Flush the selection from UV edges based on sticky modes. | ||||
| * | * | ||||
| * Useful when performing edge selections in different sticky modes, since setting the required | * Useful when performing edge selections in different sticky modes, since setting the required | ||||
| * edge flags (#MLOOPUV_EDGESEL) is done manually or using #uvedit_edge_select_set_noflush, | * edge selection is done manually or using #uvedit_edge_select_set_noflush, | ||||
| * but dealing with sticky modes for vertex selections is best done in a separate function. | * but dealing with sticky modes for vertex selections is best done in a separate function. | ||||
| * | * | ||||
| * \note Current behavior is selecting only; deselecting can be added but the behavior isn't | * \note Current behavior is selecting only; deselecting can be added but the behavior isn't | ||||
| * required anywhere. | * required anywhere. | ||||
| */ | */ | ||||
| static void uv_select_flush_from_loop_edge_flag(const Scene *scene, BMEditMesh *em) | static void uv_select_flush_from_loop_edge_flag(const Scene *scene, BMEditMesh *em) | ||||
| { | { | ||||
| const ToolSettings *ts = scene->toolsettings; | const ToolSettings *ts = scene->toolsettings; | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const char *active_uv_name = CustomData_get_active_layer_name(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| BM_uv_map_ensure_vert_select_attr(em->bm, active_uv_name); | |||||
| BM_uv_map_ensure_edge_select_attr(em->bm, active_uv_name); | |||||
| const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | |||||
| if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && | if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && | ||||
| ELEM(ts->uv_sticky, SI_STICKY_LOC, SI_STICKY_VERTEX)) { | ELEM(ts->uv_sticky, SI_STICKY_LOC, SI_STICKY_VERTEX)) { | ||||
| /* Use the #MLOOPUV_EDGESEL flag to identify which verts must to be selected */ | /* Use UV edge selection to identify which verts must to be selected */ | ||||
| struct UvVertMap *vmap; | struct UvVertMap *vmap; | ||||
| uint efa_index; | uint efa_index; | ||||
| /* Clear UV vert flags */ | /* Clear UV vert flags */ | ||||
| bm_uv_flag_clear(scene, em->bm, MLOOPUV_VERTSEL, cd_loop_uv_offset); | bm_clear_uv_vert_selection(scene, em->bm, offsets); | ||||
| BM_mesh_elem_table_ensure(em->bm, BM_FACE); | BM_mesh_elem_table_ensure(em->bm, BM_FACE); | ||||
| vmap = BM_uv_vert_map_create(em->bm, false, false); | vmap = BM_uv_vert_map_create(em->bm, false, false); | ||||
| if (vmap == NULL) { | if (vmap == NULL) { | ||||
| return; | return; | ||||
| } | } | ||||
| BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) { | BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| /* This visibility check could be removed? Simply relying on edge flags to ensure | /* This visibility check could be removed? Simply relying on edge flags to ensure | ||||
| * visibility might be sufficient. */ | * visibility might be sufficient. */ | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| MLoopUV *luv; | |||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | |||||
| /* Select verts based on UV edge flag. */ | /* Select verts based on UV edge flag. */ | ||||
| if (luv->flag & MLOOPUV_EDGESEL) { | if (BM_ELEM_CD_GET_BOOL(l, offsets.select_edge)) { | ||||
| uv_select_flush_from_tag_sticky_loc_internal( | uv_select_flush_from_tag_sticky_loc_internal( | ||||
| scene, em, vmap, efa_index, l, true, cd_loop_uv_offset); | scene, em, vmap, efa_index, l, true, offsets); | ||||
| uv_select_flush_from_tag_sticky_loc_internal( | uv_select_flush_from_tag_sticky_loc_internal( | ||||
| scene, em, vmap, efa_index, l->next, true, cd_loop_uv_offset); | scene, em, vmap, efa_index, l->next, true, offsets); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| BM_uv_vert_map_free(vmap); | BM_uv_vert_map_free(vmap); | ||||
| } | } | ||||
| else { | else { | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| MLoopUV *luv, *luv_next, *luv_prev; | |||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | if (BM_ELEM_CD_GET_BOOL(l, offsets.select_edge)) { | ||||
| luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); | BM_ELEM_CD_SET_BOOL(l, offsets.select_vert, true); | ||||
| luv_prev = BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset); | BM_ELEM_CD_SET_BOOL(l->next, offsets.select_vert, true); | ||||
| if (luv->flag & MLOOPUV_EDGESEL) { | |||||
| luv->flag |= MLOOPUV_VERTSEL; | |||||
| luv_next->flag |= MLOOPUV_VERTSEL; | |||||
| } | } | ||||
| else if (!(luv_prev->flag & MLOOPUV_EDGESEL)) { | else if (!BM_ELEM_CD_GET_BOOL(l->prev, offsets.select_edge)) { | ||||
| luv->flag &= ~MLOOPUV_VERTSEL; | BM_ELEM_CD_SET_BOOL(l->next, offsets.select_vert, false); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Box Select Operator | /** \name Box Select Operator | ||||
| * \{ */ | * \{ */ | ||||
| static int uv_box_select_exec(bContext *C, wmOperator *op) | static int uv_box_select_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); | Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); | ||||
| Scene *scene = CTX_data_scene(C); | Scene *scene = CTX_data_scene(C); | ||||
| const ToolSettings *ts = scene->toolsettings; | const ToolSettings *ts = scene->toolsettings; | ||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| const ARegion *region = CTX_wm_region(C); | const ARegion *region = CTX_wm_region(C); | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| MLoopUV *luv; | float *luv; | ||||
| rctf rectf; | rctf rectf; | ||||
| bool pinned; | bool pinned; | ||||
| const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ? | const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ? | ||||
| (ts->selectmode == SCE_SELECT_FACE) : | (ts->selectmode == SCE_SELECT_FACE) : | ||||
| (ts->uv_selectmode == UV_SELECT_FACE)); | (ts->uv_selectmode == UV_SELECT_FACE)); | ||||
| const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ? | const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ? | ||||
| (ts->selectmode == SCE_SELECT_EDGE) : | (ts->selectmode == SCE_SELECT_EDGE) : | ||||
| (ts->uv_selectmode == UV_SELECT_EDGE)); | (ts->uv_selectmode == UV_SELECT_EDGE)); | ||||
| Show All 22 Lines | static int uv_box_select_exec(bContext *C, wmOperator *op) | ||||
| /* don't indent to avoid diff noise! */ | /* don't indent to avoid diff noise! */ | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| Object *obedit = objects[ob_index]; | Object *obedit = objects[ob_index]; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| bool changed = false; | bool changed = false; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const char *active_uv_name = CustomData_get_active_layer_name(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| BM_uv_map_ensure_vert_select_attr(em->bm, active_uv_name); | |||||
| BM_uv_map_ensure_edge_select_attr(em->bm, active_uv_name); | |||||
| BM_uv_map_ensure_pin_attr(em->bm, active_uv_name); | |||||
| const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | |||||
| /* do actual selection */ | /* do actual selection */ | ||||
| if (use_face_center && !pinned) { | if (use_face_center && !pinned) { | ||||
| /* handle face selection mode */ | /* handle face selection mode */ | ||||
| float cent[2]; | float cent[2]; | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| /* assume not touched */ | /* assume not touched */ | ||||
| BM_elem_flag_disable(efa, BM_ELEM_TAG); | BM_elem_flag_disable(efa, BM_ELEM_TAG); | ||||
| if (uvedit_face_visible_test(scene, efa)) { | if (uvedit_face_visible_test(scene, efa)) { | ||||
| BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent); | BM_face_uv_calc_center_median(efa, offsets.uv, cent); | ||||
| if (BLI_rctf_isect_pt_v(&rectf, cent)) { | if (BLI_rctf_isect_pt_v(&rectf, cent)) { | ||||
| BM_elem_flag_enable(efa, BM_ELEM_TAG); | BM_elem_flag_enable(efa, BM_ELEM_TAG); | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* (de)selects all tagged faces and deals with sticky modes */ | /* (de)selects all tagged faces and deals with sticky modes */ | ||||
| if (changed) { | if (changed) { | ||||
| uv_select_flush_from_tag_face(scene, obedit, select); | uv_select_flush_from_tag_face(scene, obedit, select); | ||||
| } | } | ||||
| } | } | ||||
| else if (use_edge && !pinned) { | else if (use_edge && !pinned) { | ||||
| bool do_second_pass = true; | bool do_second_pass = true; | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev; | BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev; | ||||
| MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset); | float *luv_prev = BM_ELEM_CD_GET_FLOAT_P(l_prev, offsets.uv); | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv); | ||||
| if (BLI_rctf_isect_pt_v(&rectf, luv->uv) && BLI_rctf_isect_pt_v(&rectf, luv_prev->uv)) { | if (BLI_rctf_isect_pt_v(&rectf, luv) && BLI_rctf_isect_pt_v(&rectf, luv_prev)) { | ||||
| uvedit_edge_select_set_with_sticky( | uvedit_edge_select_set_with_sticky(scene, em, l_prev, select, false, offsets); | ||||
| scene, em, l_prev, select, false, cd_loop_uv_offset); | |||||
| changed = true; | changed = true; | ||||
| do_second_pass = false; | do_second_pass = false; | ||||
| } | } | ||||
| l_prev = l; | l_prev = l; | ||||
| luv_prev = luv; | luv_prev = luv; | ||||
| } | } | ||||
| } | } | ||||
| /* Do a second pass if no complete edges could be selected. | /* Do a second pass if no complete edges could be selected. | ||||
| * This matches wire-frame edit-mesh selection in the 3D view. */ | * This matches wire-frame edit-mesh selection in the 3D view. */ | ||||
| if (do_second_pass) { | if (do_second_pass) { | ||||
| /* Second pass to check if edges partially overlap with the selection area (box). */ | /* Second pass to check if edges partially overlap with the selection area (box). */ | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev; | BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev; | ||||
| MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset); | float *luv_prev = BM_ELEM_CD_GET_FLOAT_P(l_prev, offsets.uv); | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv); | ||||
| if (BLI_rctf_isect_segment(&rectf, luv_prev->uv, luv->uv)) { | if (BLI_rctf_isect_segment(&rectf, luv_prev, luv)) { | ||||
| uvedit_edge_select_set_with_sticky( | uvedit_edge_select_set_with_sticky(scene, em, l_prev, select, false, offsets); | ||||
| scene, em, l_prev, select, false, cd_loop_uv_offset); | |||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| l_prev = l; | l_prev = l; | ||||
| luv_prev = luv; | luv_prev = luv; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* other selection modes */ | /* other selection modes */ | ||||
| changed = true; | changed = true; | ||||
| BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); | BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| bool has_selected = false; | bool has_selected = false; | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv); | ||||
| if (select != uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { | if (select != uvedit_uv_select_test(scene, l, offsets)) { | ||||
| if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION)) { | if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION)) { | ||||
| /* UV_SYNC_SELECTION - can't do pinned selection */ | /* UV_SYNC_SELECTION - can't do pinned selection */ | ||||
| if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) { | if (BLI_rctf_isect_pt_v(&rectf, luv)) { | ||||
| uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); | uvedit_uv_select_set(scene, em->bm, l, select, false, offsets); | ||||
| BM_elem_flag_enable(l->v, BM_ELEM_TAG); | BM_elem_flag_enable(l->v, BM_ELEM_TAG); | ||||
| has_selected = true; | has_selected = true; | ||||
| } | } | ||||
| } | } | ||||
| else if (pinned) { | else if (pinned) { | ||||
| if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) { | if (BM_ELEM_CD_GET_BOOL(l, offsets.pin) && BLI_rctf_isect_pt_v(&rectf, luv)) { | ||||
| uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); | uvedit_uv_select_set(scene, em->bm, l, select, false, offsets); | ||||
| BM_elem_flag_enable(l->v, BM_ELEM_TAG); | BM_elem_flag_enable(l->v, BM_ELEM_TAG); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (has_selected && use_select_linked) { | if (has_selected && use_select_linked) { | ||||
| UvNearestHit hit = { | UvNearestHit hit = { | ||||
| .ob = obedit, | .ob = obedit, | ||||
| .efa = efa, | .efa = efa, | ||||
| }; | }; | ||||
| uv_select_linked_multi(scene, objects, objects_len, &hit, true, !select, false, false); | uv_select_linked_multi(scene, objects, objects_len, &hit, true, !select, false, false); | ||||
| } | } | ||||
| } | } | ||||
| if (ts->uv_sticky == SI_STICKY_VERTEX) { | if (ts->uv_sticky == SI_STICKY_VERTEX) { | ||||
| uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); | uvedit_vertex_select_tagged(em, scene, select, offsets); | ||||
| } | } | ||||
| } | } | ||||
| if (changed || use_pre_deselect) { | if (changed || use_pre_deselect) { | ||||
| changed_multi = true; | changed_multi = true; | ||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | if (ts->uv_flag & UV_SYNC_SELECTION) { | ||||
| ED_uvedit_select_sync_flush(ts, em, select); | ED_uvedit_select_sync_flush(ts, em, select); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | static int uv_circle_select_exec(bContext *C, wmOperator *op) | ||||
| SpaceImage *sima = CTX_wm_space_image(C); | SpaceImage *sima = CTX_wm_space_image(C); | ||||
| Scene *scene = CTX_data_scene(C); | Scene *scene = CTX_data_scene(C); | ||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| const ToolSettings *ts = scene->toolsettings; | const ToolSettings *ts = scene->toolsettings; | ||||
| const ARegion *region = CTX_wm_region(C); | const ARegion *region = CTX_wm_region(C); | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| MLoopUV *luv; | float *luv; | ||||
| int x, y, radius, width, height; | int x, y, radius, width, height; | ||||
| float zoomx, zoomy; | float zoomx, zoomy; | ||||
| float offset[2], ellipse[2]; | float offset[2], ellipse[2]; | ||||
| const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ? | const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ? | ||||
| (ts->selectmode == SCE_SELECT_FACE) : | (ts->selectmode == SCE_SELECT_FACE) : | ||||
| (ts->uv_selectmode == UV_SELECT_FACE)); | (ts->uv_selectmode == UV_SELECT_FACE)); | ||||
| const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ? | const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ? | ||||
| Show All 33 Lines | static int uv_circle_select_exec(bContext *C, wmOperator *op) | ||||
| } | } | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| Object *obedit = objects[ob_index]; | Object *obedit = objects[ob_index]; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| bool changed = false; | bool changed = false; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const char *active_uv_name = CustomData_get_active_layer_name(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| BM_uv_map_ensure_vert_select_attr(em->bm, active_uv_name); | |||||
| BM_uv_map_ensure_edge_select_attr(em->bm, active_uv_name); | |||||
| const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | |||||
| /* do selection */ | /* do selection */ | ||||
| if (use_face_center) { | if (use_face_center) { | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| BM_elem_flag_disable(efa, BM_ELEM_TAG); | BM_elem_flag_disable(efa, BM_ELEM_TAG); | ||||
| /* assume not touched */ | /* assume not touched */ | ||||
| if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { | if (select != uvedit_face_select_test(scene, efa, offsets)) { | ||||
| float cent[2]; | float cent[2]; | ||||
| BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent); | BM_face_uv_calc_center_median(efa, offsets.uv, cent); | ||||
| if (uv_circle_select_is_point_inside(cent, offset, ellipse)) { | if (uv_circle_select_is_point_inside(cent, offset, ellipse)) { | ||||
| BM_elem_flag_enable(efa, BM_ELEM_TAG); | BM_elem_flag_enable(efa, BM_ELEM_TAG); | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* (de)selects all tagged faces and deals with sticky modes */ | /* (de)selects all tagged faces and deals with sticky modes */ | ||||
| if (changed) { | if (changed) { | ||||
| uv_select_flush_from_tag_face(scene, obedit, select); | uv_select_flush_from_tag_face(scene, obedit, select); | ||||
| } | } | ||||
| } | } | ||||
| else if (use_edge) { | else if (use_edge) { | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev; | BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev; | ||||
| MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset); | float *luv_prev = BM_ELEM_CD_GET_FLOAT_P(l_prev, offsets.uv); | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv); | ||||
| if (uv_circle_select_is_edge_inside(luv->uv, luv_prev->uv, offset, ellipse)) { | if (uv_circle_select_is_edge_inside(luv, luv_prev, offset, ellipse)) { | ||||
| uvedit_edge_select_set_with_sticky( | uvedit_edge_select_set_with_sticky(scene, em, l_prev, select, false, offsets); | ||||
| scene, em, l_prev, select, false, cd_loop_uv_offset); | |||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| l_prev = l; | l_prev = l; | ||||
| luv_prev = luv; | luv_prev = luv; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); | BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| bool has_selected = false; | bool has_selected = false; | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| if (select != uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { | if (select != uvedit_uv_select_test(scene, l, offsets)) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv); | ||||
| if (uv_circle_select_is_point_inside(luv->uv, offset, ellipse)) { | if (uv_circle_select_is_point_inside(luv, offset, ellipse)) { | ||||
| changed = true; | changed = true; | ||||
| uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); | uvedit_uv_select_set(scene, em->bm, l, select, false, offsets); | ||||
| BM_elem_flag_enable(l->v, BM_ELEM_TAG); | BM_elem_flag_enable(l->v, BM_ELEM_TAG); | ||||
| has_selected = true; | has_selected = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (has_selected && use_select_linked) { | if (has_selected && use_select_linked) { | ||||
| UvNearestHit hit = { | UvNearestHit hit = { | ||||
| .ob = obedit, | .ob = obedit, | ||||
| .efa = efa, | .efa = efa, | ||||
| }; | }; | ||||
| uv_select_linked_multi(scene, objects, objects_len, &hit, true, !select, false, false); | uv_select_linked_multi(scene, objects, objects_len, &hit, true, !select, false, false); | ||||
| } | } | ||||
| } | } | ||||
| if (ts->uv_sticky == SI_STICKY_VERTEX) { | if (ts->uv_sticky == SI_STICKY_VERTEX) { | ||||
| uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); | uvedit_vertex_select_tagged(em, scene, select, offsets); | ||||
| } | } | ||||
| } | } | ||||
| if (changed || use_pre_deselect) { | if (changed || use_pre_deselect) { | ||||
| changed_multi = true; | changed_multi = true; | ||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | if (ts->uv_flag & UV_SYNC_SELECTION) { | ||||
| ED_uvedit_select_sync_flush(ts, em, select); | ED_uvedit_select_sync_flush(ts, em, select); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 113 Lines • ▼ Show 20 Lines | static bool do_lasso_select_mesh_uv(bContext *C, | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| Object *obedit = objects[ob_index]; | Object *obedit = objects[ob_index]; | ||||
| bool changed = false; | bool changed = false; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const char *active_uv_name = CustomData_get_active_layer_name(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| BM_uv_map_ensure_vert_select_attr(em->bm, active_uv_name); | |||||
| BM_uv_map_ensure_edge_select_attr(em->bm, active_uv_name); | |||||
| const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | |||||
| if (use_face_center) { /* Face Center Select. */ | if (use_face_center) { /* Face Center Select. */ | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| BM_elem_flag_disable(efa, BM_ELEM_TAG); | BM_elem_flag_disable(efa, BM_ELEM_TAG); | ||||
| /* assume not touched */ | /* assume not touched */ | ||||
| if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { | if (select != uvedit_face_select_test(scene, efa, offsets)) { | ||||
| float cent[2]; | float cent[2]; | ||||
| BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent); | BM_face_uv_calc_center_median(efa, offsets.uv, cent); | ||||
| if (do_lasso_select_mesh_uv_is_point_inside(region, &rect, mcoords, mcoords_len, cent)) { | if (do_lasso_select_mesh_uv_is_point_inside(region, &rect, mcoords, mcoords_len, cent)) { | ||||
| BM_elem_flag_enable(efa, BM_ELEM_TAG); | BM_elem_flag_enable(efa, BM_ELEM_TAG); | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* (de)selects all tagged faces and deals with sticky modes */ | /* (de)selects all tagged faces and deals with sticky modes */ | ||||
| if (changed) { | if (changed) { | ||||
| uv_select_flush_from_tag_face(scene, obedit, select); | uv_select_flush_from_tag_face(scene, obedit, select); | ||||
| } | } | ||||
| } | } | ||||
| else if (use_edge) { | else if (use_edge) { | ||||
| bool do_second_pass = true; | bool do_second_pass = true; | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev; | BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev; | ||||
| MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset); | float *luv_prev = BM_ELEM_CD_GET_FLOAT_P(l_prev, offsets.uv); | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | float *luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv); | ||||
| if (do_lasso_select_mesh_uv_is_point_inside( | if (do_lasso_select_mesh_uv_is_point_inside(region, &rect, mcoords, mcoords_len, luv) && | ||||
| region, &rect, mcoords, mcoords_len, luv->uv) && | |||||
| do_lasso_select_mesh_uv_is_point_inside( | do_lasso_select_mesh_uv_is_point_inside( | ||||
| region, &rect, mcoords, mcoords_len, luv_prev->uv)) { | region, &rect, mcoords, mcoords_len, luv_prev)) { | ||||
| uvedit_edge_select_set_with_sticky( | uvedit_edge_select_set_with_sticky(scene, em, l_prev, select, false, offsets); | ||||
| scene, em, l_prev, select, false, cd_loop_uv_offset); | |||||
| do_second_pass = false; | do_second_pass = false; | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| l_prev = l; | l_prev = l; | ||||
| luv_prev = luv; | luv_prev = luv; | ||||
| } | } | ||||
| } | } | ||||
| /* Do a second pass if no complete edges could be selected. | /* Do a second pass if no complete edges could be selected. | ||||
| * This matches wire-frame edit-mesh selection in the 3D view. */ | * This matches wire-frame edit-mesh selection in the 3D view. */ | ||||
| if (do_second_pass) { | if (do_second_pass) { | ||||
| /* Second pass to check if edges partially overlap with the selection area (lasso). */ | /* Second pass to check if edges partially overlap with the selection area (lasso). */ | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev; | BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev; | ||||
| MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset); | float *luv_prev = BM_ELEM_CD_GET_FLOAT_P(l_prev, offsets.uv); | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | float *luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv); | ||||
| if (do_lasso_select_mesh_uv_is_edge_inside( | if (do_lasso_select_mesh_uv_is_edge_inside( | ||||
| region, &rect, mcoords, mcoords_len, luv->uv, luv_prev->uv)) { | region, &rect, mcoords, mcoords_len, luv, luv_prev)) { | ||||
| uvedit_edge_select_set_with_sticky( | uvedit_edge_select_set_with_sticky(scene, em, l_prev, select, false, offsets); | ||||
| scene, em, l_prev, select, false, cd_loop_uv_offset); | |||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| l_prev = l; | l_prev = l; | ||||
| luv_prev = luv; | luv_prev = luv; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { /* Vert Selection. */ | else { /* Vert Selection. */ | ||||
| BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); | BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| bool has_selected = false; | bool has_selected = false; | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| if (select != uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { | if (select != uvedit_uv_select_test(scene, l, offsets)) { | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | float *luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv); | ||||
| if (do_lasso_select_mesh_uv_is_point_inside( | if (do_lasso_select_mesh_uv_is_point_inside( | ||||
| region, &rect, mcoords, mcoords_len, luv->uv)) { | region, &rect, mcoords, mcoords_len, luv)) { | ||||
| uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); | uvedit_uv_select_set(scene, em->bm, l, select, false, offsets); | ||||
| changed = true; | changed = true; | ||||
| BM_elem_flag_enable(l->v, BM_ELEM_TAG); | BM_elem_flag_enable(l->v, BM_ELEM_TAG); | ||||
| has_selected = true; | has_selected = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (has_selected && use_select_linked) { | if (has_selected && use_select_linked) { | ||||
| UvNearestHit hit = { | UvNearestHit hit = { | ||||
| .ob = obedit, | .ob = obedit, | ||||
| .efa = efa, | .efa = efa, | ||||
| }; | }; | ||||
| uv_select_linked_multi(scene, objects, objects_len, &hit, true, !select, false, false); | uv_select_linked_multi(scene, objects, objects_len, &hit, true, !select, false, false); | ||||
| } | } | ||||
| } | } | ||||
| if (ts->uv_sticky == SI_STICKY_VERTEX) { | if (ts->uv_sticky == SI_STICKY_VERTEX) { | ||||
| uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); | uvedit_vertex_select_tagged(em, scene, select, offsets); | ||||
| } | } | ||||
| } | } | ||||
| if (changed || use_pre_deselect) { | if (changed || use_pre_deselect) { | ||||
| changed_multi = true; | changed_multi = true; | ||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | if (ts->uv_flag & UV_SYNC_SELECTION) { | ||||
| ED_uvedit_select_sync_flush(ts, em, select); | ED_uvedit_select_sync_flush(ts, em, select); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) { | ||||
| } | } | ||||
| } | } | ||||
| Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); | Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); | ||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| MLoopUV *luv; | |||||
| uint objects_len = 0; | uint objects_len = 0; | ||||
| Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( | Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( | ||||
| scene, view_layer, ((View3D *)NULL), &objects_len); | scene, view_layer, ((View3D *)NULL), &objects_len); | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| Object *obedit = objects[ob_index]; | Object *obedit = objects[ob_index]; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | |||||
| bool changed = false; | bool changed = false; | ||||
| const char *active_uv_name = CustomData_get_active_layer_name(&em->bm->ldata, CD_PROP_FLOAT2); | |||||
| BM_uv_map_ensure_vert_select_attr(em->bm, active_uv_name); | |||||
| BM_uv_map_ensure_edge_select_attr(em->bm, active_uv_name); | |||||
| BM_uv_map_ensure_pin_attr(em->bm, active_uv_name); | |||||
| const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | |||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | |||||
| if (luv->flag & MLOOPUV_PINNED) { | if (BM_ELEM_CD_GET_BOOL(l, offsets.pin)) { | ||||
| uvedit_uv_select_enable(scene, em->bm, l, false, cd_loop_uv_offset); | uvedit_uv_select_enable(scene, em->bm, l, false, offsets); | ||||
Done Inline Actions(picky) Add brackets: chrisbblend: (picky) Add brackets:
`if (BM_ELEM_CD_GET_BOOL (l, offsets.pin)) {` | |||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) { | if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) { | ||||
| ED_uvedit_selectmode_flush(scene, em); | ED_uvedit_selectmode_flush(scene, em); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 143 Lines • ▼ Show 20 Lines | static int uv_select_overlap(bContext *C, const bool extend) | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| Object *obedit = objects[ob_index]; | Object *obedit = objects[ob_index]; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| /* Triangulate each UV face and store it inside the BVH. */ | /* Triangulate each UV face and store it inside the BVH. */ | ||||
| int face_index; | int face_index; | ||||
| BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, face_index) { | BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, face_index) { | ||||
| if (!uvedit_face_visible_test_ex(scene->toolsettings, efa)) { | if (!uvedit_face_visible_test_ex(scene->toolsettings, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| const uint face_len = efa->len; | const uint face_len = efa->len; | ||||
| const uint tri_len = face_len - 2; | const uint tri_len = face_len - 2; | ||||
| if (face_len_alloc < face_len) { | if (face_len_alloc < face_len) { | ||||
| MEM_freeN(uv_verts); | MEM_freeN(uv_verts); | ||||
| MEM_freeN(indices); | MEM_freeN(indices); | ||||
| uv_verts = MEM_mallocN(sizeof(*uv_verts) * face_len, "UvOverlapCoords"); | uv_verts = MEM_mallocN(sizeof(*uv_verts) * face_len, "UvOverlapCoords"); | ||||
| indices = MEM_mallocN(sizeof(*indices) * tri_len, "UvOverlapTris"); | indices = MEM_mallocN(sizeof(*indices) * tri_len, "UvOverlapTris"); | ||||
| face_len_alloc = face_len; | face_len_alloc = face_len; | ||||
| } | } | ||||
| int vert_index; | int vert_index; | ||||
| BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, vert_index) { | BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, vert_index) { | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | float *luv = BM_ELEM_CD_GET_FLOAT_P(l, cd_loop_uv_offset); | ||||
| copy_v2_v2(uv_verts[vert_index], luv->uv); | copy_v2_v2(uv_verts[vert_index], luv); | ||||
| } | } | ||||
| BLI_polyfill_calc(uv_verts, face_len, 0, indices); | BLI_polyfill_calc(uv_verts, face_len, 0, indices); | ||||
| for (int t = 0; t < tri_len; t++) { | for (int t = 0; t < tri_len; t++) { | ||||
| overlap_data[data_index].ob_index = ob_index; | overlap_data[data_index].ob_index = ob_index; | ||||
| overlap_data[data_index].face_index = face_index; | overlap_data[data_index].face_index = face_index; | ||||
| Show All 40 Lines | for (int i = 0; i < tree_overlap_len; i++) { | ||||
| const struct UVOverlapData *o_a = &overlap_data[overlap[i].indexA]; | const struct UVOverlapData *o_a = &overlap_data[overlap[i].indexA]; | ||||
| const struct UVOverlapData *o_b = &overlap_data[overlap[i].indexB]; | const struct UVOverlapData *o_b = &overlap_data[overlap[i].indexB]; | ||||
| Object *obedit_a = objects[o_a->ob_index]; | Object *obedit_a = objects[o_a->ob_index]; | ||||
| Object *obedit_b = objects[o_b->ob_index]; | Object *obedit_b = objects[o_b->ob_index]; | ||||
| BMEditMesh *em_a = BKE_editmesh_from_object(obedit_a); | BMEditMesh *em_a = BKE_editmesh_from_object(obedit_a); | ||||
| BMEditMesh *em_b = BKE_editmesh_from_object(obedit_b); | BMEditMesh *em_b = BKE_editmesh_from_object(obedit_b); | ||||
| BMFace *face_a = em_a->bm->ftable[o_a->face_index]; | BMFace *face_a = em_a->bm->ftable[o_a->face_index]; | ||||
| BMFace *face_b = em_b->bm->ftable[o_b->face_index]; | BMFace *face_b = em_b->bm->ftable[o_b->face_index]; | ||||
| const int cd_loop_uv_offset_a = CustomData_get_offset(&em_a->bm->ldata, CD_MLOOPUV); | const char *uv_a_name = CustomData_get_active_layer_name(&em_a->bm->ldata, CD_PROP_FLOAT2); | ||||
| const int cd_loop_uv_offset_b = CustomData_get_offset(&em_b->bm->ldata, CD_MLOOPUV); | const char *uv_b_name = CustomData_get_active_layer_name(&em_b->bm->ldata, CD_PROP_FLOAT2); | ||||
| BM_uv_map_ensure_vert_select_attr(em_a->bm, uv_a_name); | |||||
| BM_uv_map_ensure_vert_select_attr(em_b->bm, uv_b_name); | |||||
| BM_uv_map_ensure_edge_select_attr(em_a->bm, uv_a_name); | |||||
| BM_uv_map_ensure_edge_select_attr(em_b->bm, uv_b_name); | |||||
| const BMUVOffsets offsets_a = BM_uv_map_get_offsets(em_a->bm); | |||||
| const BMUVOffsets offsets_b = BM_uv_map_get_offsets(em_b->bm); | |||||
| /* Skip if both faces are already selected. */ | /* Skip if both faces are already selected. */ | ||||
| if (uvedit_face_select_test(scene, face_a, cd_loop_uv_offset_a) && | if (uvedit_face_select_test(scene, face_a, offsets_a) && | ||||
| uvedit_face_select_test(scene, face_b, cd_loop_uv_offset_b)) { | uvedit_face_select_test(scene, face_b, offsets_b)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* Main tri-tri overlap test. */ | /* Main tri-tri overlap test. */ | ||||
| const float endpoint_bias = -1e-4f; | const float endpoint_bias = -1e-4f; | ||||
| if (overlap_tri_tri_uv_test(o_a->tri, o_b->tri, endpoint_bias)) { | if (overlap_tri_tri_uv_test(o_a->tri, o_b->tri, endpoint_bias)) { | ||||
| uvedit_face_select_enable(scene, em_a->bm, face_a, false, cd_loop_uv_offset_a); | uvedit_face_select_enable(scene, em_a->bm, face_a, false, offsets_a); | ||||
| uvedit_face_select_enable(scene, em_b->bm, face_b, false, cd_loop_uv_offset_b); | uvedit_face_select_enable(scene, em_b->bm, face_b, false, offsets_b); | ||||
| } | } | ||||
| } | } | ||||
| BLI_gset_free(overlap_set, NULL); | BLI_gset_free(overlap_set, NULL); | ||||
| MEM_freeN(overlap); | MEM_freeN(overlap); | ||||
| } | } | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| Show All 36 Lines | |||||
| /** \} */ | /** \} */ | ||||
| /** \name Select Similar Operator | /** \name Select Similar Operator | ||||
| * \{ */ | * \{ */ | ||||
| static float get_uv_vert_needle(const eUVSelectSimilar type, | static float get_uv_vert_needle(const eUVSelectSimilar type, | ||||
| BMVert *vert, | BMVert *vert, | ||||
| const float ob_m3[3][3], | const float ob_m3[3][3], | ||||
| MLoopUV *luv, | BMLoop *loop, | ||||
| const int cd_loop_uv_offset) | const BMUVOffsets offsets) | ||||
| { | { | ||||
| BLI_assert(offsets.pin >= 0); | |||||
| BLI_assert(offsets.uv >= 0); | |||||
| float result = 0.0f; | float result = 0.0f; | ||||
| switch (type) { | switch (type) { | ||||
| case UV_SSIM_AREA_UV: { | case UV_SSIM_AREA_UV: { | ||||
| BMFace *f; | BMFace *f; | ||||
| BMIter iter; | BMIter iter; | ||||
| BM_ITER_ELEM (f, &iter, vert, BM_FACES_OF_VERT) { | BM_ITER_ELEM (f, &iter, vert, BM_FACES_OF_VERT) { | ||||
| result += BM_face_calc_area_uv(f, cd_loop_uv_offset); | result += BM_face_calc_area_uv(f, offsets.uv); | ||||
| } | } | ||||
| } break; | } break; | ||||
| case UV_SSIM_AREA_3D: { | case UV_SSIM_AREA_3D: { | ||||
| BMFace *f; | BMFace *f; | ||||
| BMIter iter; | BMIter iter; | ||||
| BM_ITER_ELEM (f, &iter, vert, BM_FACES_OF_VERT) { | BM_ITER_ELEM (f, &iter, vert, BM_FACES_OF_VERT) { | ||||
| result += BM_face_calc_area_with_mat3(f, ob_m3); | result += BM_face_calc_area_with_mat3(f, ob_m3); | ||||
| } | } | ||||
| } break; | } break; | ||||
| case UV_SSIM_SIDES: { | case UV_SSIM_SIDES: { | ||||
| BMEdge *e; | BMEdge *e; | ||||
| BMIter iter; | BMIter iter; | ||||
| BM_ITER_ELEM (e, &iter, vert, BM_EDGES_OF_VERT) { | BM_ITER_ELEM (e, &iter, vert, BM_EDGES_OF_VERT) { | ||||
| result += 1.0f; | result += 1.0f; | ||||
| } | } | ||||
| } break; | } break; | ||||
| case UV_SSIM_PIN: | case UV_SSIM_PIN: | ||||
| return (luv->flag & MLOOPUV_PINNED) ? 1.0f : 0.0f; | return (BM_ELEM_CD_GET_BOOL(loop, offsets.pin)) ? 1.0f : 0.0f; | ||||
| default: | default: | ||||
| BLI_assert_unreachable(); | BLI_assert_unreachable(); | ||||
| return false; | return false; | ||||
| } | } | ||||
| return result; | return result; | ||||
| } | } | ||||
| static float get_uv_edge_needle(const eUVSelectSimilar type, | static float get_uv_edge_needle(const eUVSelectSimilar type, | ||||
| BMEdge *edge, | BMEdge *edge, | ||||
| const float ob_m3[3][3], | const float ob_m3[3][3], | ||||
| MLoopUV *luv_a, | BMLoop *loop_a, | ||||
| MLoopUV *luv_b, | BMLoop *loop_b, | ||||
| const int cd_loop_uv_offset) | const BMUVOffsets offsets) | ||||
| { | { | ||||
| BLI_assert(offsets.pin >= 0); | |||||
| BLI_assert(offsets.uv >= 0); | |||||
| float result = 0.0f; | float result = 0.0f; | ||||
| switch (type) { | switch (type) { | ||||
| case UV_SSIM_AREA_UV: { | case UV_SSIM_AREA_UV: { | ||||
| BMFace *f; | BMFace *f; | ||||
| BMIter iter; | BMIter iter; | ||||
| BM_ITER_ELEM (f, &iter, edge, BM_FACES_OF_EDGE) { | BM_ITER_ELEM (f, &iter, edge, BM_FACES_OF_EDGE) { | ||||
| result += BM_face_calc_area_uv(f, cd_loop_uv_offset); | result += BM_face_calc_area_uv(f, offsets.uv); | ||||
| } | } | ||||
| } break; | } break; | ||||
| case UV_SSIM_AREA_3D: { | case UV_SSIM_AREA_3D: { | ||||
| BMFace *f; | BMFace *f; | ||||
| BMIter iter; | BMIter iter; | ||||
| BM_ITER_ELEM (f, &iter, edge, BM_FACES_OF_EDGE) { | BM_ITER_ELEM (f, &iter, edge, BM_FACES_OF_EDGE) { | ||||
| result += BM_face_calc_area_with_mat3(f, ob_m3); | result += BM_face_calc_area_with_mat3(f, ob_m3); | ||||
| } | } | ||||
| } break; | } break; | ||||
| case UV_SSIM_LENGTH_UV: | case UV_SSIM_LENGTH_UV: { | ||||
| return len_v2v2(luv_a->uv, luv_b->uv); | float *luv_a = BM_ELEM_CD_GET_FLOAT_P(loop_a, offsets.uv); | ||||
| float *luv_b = BM_ELEM_CD_GET_FLOAT_P(loop_b, offsets.uv); | |||||
| return len_v2v2(luv_a, luv_b); | |||||
| } break; | |||||
| case UV_SSIM_LENGTH_3D: | case UV_SSIM_LENGTH_3D: | ||||
| return len_v3v3(edge->v1->co, edge->v2->co); | return len_v3v3(edge->v1->co, edge->v2->co); | ||||
| case UV_SSIM_SIDES: { | case UV_SSIM_SIDES: { | ||||
| BMEdge *e; | BMEdge *e; | ||||
| BMIter iter; | BMIter iter; | ||||
| BM_ITER_ELEM (e, &iter, edge, BM_FACES_OF_EDGE) { | BM_ITER_ELEM (e, &iter, edge, BM_FACES_OF_EDGE) { | ||||
| result += 1.0f; | result += 1.0f; | ||||
| } | } | ||||
| } break; | } break; | ||||
| case UV_SSIM_PIN: | case UV_SSIM_PIN: | ||||
| if (luv_a->flag & MLOOPUV_PINNED) { | if (BM_ELEM_CD_GET_BOOL(loop_a, offsets.pin)) { | ||||
| result += 1.0f; | result += 1.0f; | ||||
| } | } | ||||
| if (luv_b->flag & MLOOPUV_PINNED) { | if (BM_ELEM_CD_GET_BOOL(loop_b, offsets.pin)) { | ||||
| result += 1.0f; | result += 1.0f; | ||||
| } | } | ||||
| break; | break; | ||||
| default: | default: | ||||
| BLI_assert_unreachable(); | BLI_assert_unreachable(); | ||||
| return false; | return false; | ||||
| } | } | ||||
| return result; | return result; | ||||
| } | } | ||||
| static float get_uv_face_needle(const eUVSelectSimilar type, | static float get_uv_face_needle(const eUVSelectSimilar type, | ||||
| BMFace *face, | BMFace *face, | ||||
| const float ob_m3[3][3], | const float ob_m3[3][3], | ||||
| const int cd_loop_uv_offset) | const BMUVOffsets offsets) | ||||
| { | { | ||||
| BLI_assert(offsets.pin >= 0); | |||||
| BLI_assert(offsets.uv >= 0); | |||||
| float result = 0.0f; | float result = 0.0f; | ||||
| switch (type) { | switch (type) { | ||||
| case UV_SSIM_AREA_UV: | case UV_SSIM_AREA_UV: | ||||
| return BM_face_calc_area_uv(face, cd_loop_uv_offset); | return BM_face_calc_area_uv(face, offsets.uv); | ||||
| case UV_SSIM_AREA_3D: | case UV_SSIM_AREA_3D: | ||||
| return BM_face_calc_area_with_mat3(face, ob_m3); | return BM_face_calc_area_with_mat3(face, ob_m3); | ||||
| case UV_SSIM_SIDES: | case UV_SSIM_SIDES: | ||||
| return face->len; | return face->len; | ||||
| case UV_SSIM_PIN: { | case UV_SSIM_PIN: { | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter liter; | BMIter liter; | ||||
| BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) { | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | if (BM_ELEM_CD_GET_BOOL(l, offsets.pin)) { | ||||
| if (luv->flag & MLOOPUV_PINNED) { | |||||
| result += 1.0f; | result += 1.0f; | ||||
| } | } | ||||
| } | } | ||||
| } break; | } break; | ||||
| case UV_SSIM_MATERIAL: | case UV_SSIM_MATERIAL: | ||||
| return face->mat_nr; | return face->mat_nr; | ||||
| default: | default: | ||||
| BLI_assert_unreachable(); | BLI_assert_unreachable(); | ||||
| return false; | return false; | ||||
| } | } | ||||
| return result; | return result; | ||||
| } | } | ||||
| static float get_uv_island_needle(const eUVSelectSimilar type, | static float get_uv_island_needle(const eUVSelectSimilar type, | ||||
| const struct FaceIsland *island, | const struct FaceIsland *island, | ||||
| const float ob_m3[3][3], | const float ob_m3[3][3], | ||||
| const int cd_loop_uv_offset) | const BMUVOffsets offsets) | ||||
| { | { | ||||
| BLI_assert(offsets.uv >= 0); | |||||
| float result = 0.0f; | float result = 0.0f; | ||||
| switch (type) { | switch (type) { | ||||
| case UV_SSIM_AREA_UV: | case UV_SSIM_AREA_UV: | ||||
| for (int i = 0; i < island->faces_len; i++) { | for (int i = 0; i < island->faces_len; i++) { | ||||
| result += BM_face_calc_area_uv(island->faces[i], cd_loop_uv_offset); | result += BM_face_calc_area_uv(island->faces[i], offsets.uv); | ||||
| } | } | ||||
| break; | break; | ||||
| case UV_SSIM_AREA_3D: | case UV_SSIM_AREA_3D: | ||||
| for (int i = 0; i < island->faces_len; i++) { | for (int i = 0; i < island->faces_len; i++) { | ||||
| result += BM_face_calc_area_with_mat3(island->faces[i], ob_m3); | result += BM_face_calc_area_with_mat3(island->faces[i], ob_m3); | ||||
| } | } | ||||
| break; | break; | ||||
| case UV_SSIM_FACE: | case UV_SSIM_FACE: | ||||
| ▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | static int uv_select_similar_vert_exec(bContext *C, wmOperator *op) | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| Object *ob = objects[ob_index]; | Object *ob = objects[ob_index]; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(ob); | BMEditMesh *em = BKE_editmesh_from_object(ob); | ||||
| BMesh *bm = em->bm; | BMesh *bm = em->bm; | ||||
| if (bm->totvertsel == 0) { | if (bm->totvertsel == 0) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(bm); | ||||
| float ob_m3[3][3]; | float ob_m3[3][3]; | ||||
| copy_m3_m4(ob_m3, ob->object_to_world); | copy_m3_m4(ob_m3, ob->object_to_world); | ||||
| BMFace *face; | BMFace *face; | ||||
| BMIter iter; | BMIter iter; | ||||
| BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, face)) { | if (!uvedit_face_visible_test(scene, face)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter liter; | BMIter liter; | ||||
| BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) { | ||||
| if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { | if (!uvedit_uv_select_test(scene, l, offsets)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | float needle = get_uv_vert_needle(type, l->v, ob_m3, l, offsets); | ||||
| float needle = get_uv_vert_needle(type, l->v, ob_m3, luv, cd_loop_uv_offset); | |||||
| BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle); | BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (tree_1d != NULL) { | if (tree_1d != NULL) { | ||||
| BLI_kdtree_1d_deduplicate(tree_1d); | BLI_kdtree_1d_deduplicate(tree_1d); | ||||
| BLI_kdtree_1d_balance(tree_1d); | BLI_kdtree_1d_balance(tree_1d); | ||||
| } | } | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| Object *ob = objects[ob_index]; | Object *ob = objects[ob_index]; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(ob); | BMEditMesh *em = BKE_editmesh_from_object(ob); | ||||
| BMesh *bm = em->bm; | BMesh *bm = em->bm; | ||||
| if (bm->totvertsel == 0) { | if (bm->totvertsel == 0) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| bool changed = false; | bool changed = false; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); | |||||
| const BMUVOffsets offsets = BM_uv_map_get_offsets(bm); | |||||
| float ob_m3[3][3]; | float ob_m3[3][3]; | ||||
| copy_m3_m4(ob_m3, ob->object_to_world); | copy_m3_m4(ob_m3, ob->object_to_world); | ||||
| BMFace *face; | BMFace *face; | ||||
| BMIter iter; | BMIter iter; | ||||
| BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, face)) { | if (!uvedit_face_visible_test(scene, face)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter liter; | BMIter liter; | ||||
| BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) { | ||||
| if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { | if (uvedit_uv_select_test(scene, l, offsets)) { | ||||
| continue; /* Already selected. */ | continue; /* Already selected. */ | ||||
| } | } | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | const float needle = get_uv_vert_needle(type, l->v, ob_m3, l, offsets); | ||||
| const float needle = get_uv_vert_needle(type, l->v, ob_m3, luv, cd_loop_uv_offset); | |||||
| bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare); | bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare); | ||||
| if (select) { | if (select) { | ||||
| uvedit_uv_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); | uvedit_uv_select_set(scene, em->bm, l, select, false, offsets); | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| if (changed) { | if (changed) { | ||||
| uv_select_tag_update_for_object(depsgraph, ts, ob); | uv_select_tag_update_for_object(depsgraph, ts, ob); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| Show All 39 Lines | static int uv_select_similar_edge_exec(bContext *C, wmOperator *op) | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| Object *ob = objects[ob_index]; | Object *ob = objects[ob_index]; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(ob); | BMEditMesh *em = BKE_editmesh_from_object(ob); | ||||
| BMesh *bm = em->bm; | BMesh *bm = em->bm; | ||||
| if (bm->totvertsel == 0) { | if (bm->totvertsel == 0) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(bm); | ||||
| float ob_m3[3][3]; | float ob_m3[3][3]; | ||||
| copy_m3_m4(ob_m3, ob->object_to_world); | copy_m3_m4(ob_m3, ob->object_to_world); | ||||
| BMFace *face; | BMFace *face; | ||||
| BMIter iter; | BMIter iter; | ||||
| BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, face)) { | if (!uvedit_face_visible_test(scene, face)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter liter; | BMIter liter; | ||||
| BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) { | ||||
| if (!uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) { | if (!uvedit_edge_select_test(scene, l, offsets)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| MLoopUV *luv_a = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | float needle = get_uv_edge_needle(type, l->e, ob_m3, l, l->next, offsets); | ||||
| MLoopUV *luv_b = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); | |||||
| float needle = get_uv_edge_needle(type, l->e, ob_m3, luv_a, luv_b, cd_loop_uv_offset); | |||||
| if (tree_1d) { | if (tree_1d) { | ||||
| BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle); | BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (tree_1d != NULL) { | if (tree_1d != NULL) { | ||||
| BLI_kdtree_1d_deduplicate(tree_1d); | BLI_kdtree_1d_deduplicate(tree_1d); | ||||
| BLI_kdtree_1d_balance(tree_1d); | BLI_kdtree_1d_balance(tree_1d); | ||||
| } | } | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| Object *ob = objects[ob_index]; | Object *ob = objects[ob_index]; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(ob); | BMEditMesh *em = BKE_editmesh_from_object(ob); | ||||
| BMesh *bm = em->bm; | BMesh *bm = em->bm; | ||||
| if (bm->totvertsel == 0) { | if (bm->totvertsel == 0) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| bool changed = false; | bool changed = false; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(bm); | ||||
| float ob_m3[3][3]; | float ob_m3[3][3]; | ||||
| copy_m3_m4(ob_m3, ob->object_to_world); | copy_m3_m4(ob_m3, ob->object_to_world); | ||||
| BMFace *face; | BMFace *face; | ||||
| BMIter iter; | BMIter iter; | ||||
| BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, face)) { | if (!uvedit_face_visible_test(scene, face)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter liter; | BMIter liter; | ||||
| BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) { | ||||
| if (uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) { | if (uvedit_edge_select_test(scene, l, offsets)) { | ||||
| continue; /* Already selected. */ | continue; /* Already selected. */ | ||||
| } | } | ||||
| MLoopUV *luv_a = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | float needle = get_uv_edge_needle(type, l->e, ob_m3, l, l->next, offsets); | ||||
| MLoopUV *luv_b = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); | |||||
| float needle = get_uv_edge_needle(type, l->e, ob_m3, luv_a, luv_b, cd_loop_uv_offset); | |||||
| bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare); | bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare); | ||||
| if (select) { | if (select) { | ||||
| uvedit_edge_select_set(scene, em->bm, l, select, false, cd_loop_uv_offset); | uvedit_edge_select_set(scene, em->bm, l, select, false, offsets); | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| if (changed) { | if (changed) { | ||||
| uv_select_tag_update_for_object(depsgraph, ts, ob); | uv_select_tag_update_for_object(depsgraph, ts, ob); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| Show All 33 Lines | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| Object *ob = objects[ob_index]; | Object *ob = objects[ob_index]; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(ob); | BMEditMesh *em = BKE_editmesh_from_object(ob); | ||||
| BMesh *bm = em->bm; | BMesh *bm = em->bm; | ||||
| float ob_m3[3][3]; | float ob_m3[3][3]; | ||||
| copy_m3_m4(ob_m3, ob->object_to_world); | copy_m3_m4(ob_m3, ob->object_to_world); | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(bm); | ||||
| BMFace *face; | BMFace *face; | ||||
| BMIter iter; | BMIter iter; | ||||
| BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, face)) { | if (!uvedit_face_visible_test(scene, face)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (!uvedit_face_select_test(scene, face, cd_loop_uv_offset)) { | if (!uvedit_face_select_test(scene, face, offsets)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| float needle = get_uv_face_needle(type, face, ob_m3, cd_loop_uv_offset); | float needle = get_uv_face_needle(type, face, ob_m3, offsets); | ||||
| if (tree_1d) { | if (tree_1d) { | ||||
| BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle); | BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (tree_1d != NULL) { | if (tree_1d != NULL) { | ||||
| BLI_kdtree_1d_deduplicate(tree_1d); | BLI_kdtree_1d_deduplicate(tree_1d); | ||||
| BLI_kdtree_1d_balance(tree_1d); | BLI_kdtree_1d_balance(tree_1d); | ||||
| } | } | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| Object *ob = objects[ob_index]; | Object *ob = objects[ob_index]; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(ob); | BMEditMesh *em = BKE_editmesh_from_object(ob); | ||||
| BMesh *bm = em->bm; | BMesh *bm = em->bm; | ||||
| bool changed = false; | bool changed = false; | ||||
| bool do_history = false; | bool do_history = false; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(bm); | ||||
| float ob_m3[3][3]; | float ob_m3[3][3]; | ||||
| copy_m3_m4(ob_m3, ob->object_to_world); | copy_m3_m4(ob_m3, ob->object_to_world); | ||||
| BMFace *face; | BMFace *face; | ||||
| BMIter iter; | BMIter iter; | ||||
| BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, face)) { | if (!uvedit_face_visible_test(scene, face)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (uvedit_face_select_test(scene, face, cd_loop_uv_offset)) { | if (uvedit_face_select_test(scene, face, offsets)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| float needle = get_uv_face_needle(type, face, ob_m3, cd_loop_uv_offset); | float needle = get_uv_face_needle(type, face, ob_m3, offsets); | ||||
| bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare); | bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare); | ||||
| if (select) { | if (select) { | ||||
| uvedit_face_select_set(scene, em->bm, face, select, do_history, cd_loop_uv_offset); | uvedit_face_select_set(scene, bm, face, select, do_history, offsets); | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| if (changed) { | if (changed) { | ||||
| uv_select_tag_update_for_object(depsgraph, ts, ob); | uv_select_tag_update_for_object(depsgraph, ts, ob); | ||||
| } | } | ||||
| } | } | ||||
| MEM_SAFE_FREE(objects); | MEM_SAFE_FREE(objects); | ||||
| BLI_kdtree_1d_free(tree_1d); | BLI_kdtree_1d_free(tree_1d); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| static bool uv_island_selected(const Scene *scene, struct FaceIsland *island) | static bool uv_island_selected(const Scene *scene, struct FaceIsland *island) | ||||
| { | { | ||||
| BLI_assert(island && island->faces_len); | BLI_assert(island && island->faces_len); | ||||
| return uvedit_face_select_test(scene, island->faces[0], island->cd_loop_uv_offset); | return uvedit_face_select_test(scene, island->faces[0], island->offsets); | ||||
| } | } | ||||
| static int uv_select_similar_island_exec(bContext *C, wmOperator *op) | static int uv_select_similar_island_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| Scene *scene = CTX_data_scene(C); | Scene *scene = CTX_data_scene(C); | ||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); | Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); | ||||
| ToolSettings *ts = CTX_data_tool_settings(C); | ToolSettings *ts = CTX_data_tool_settings(C); | ||||
| Show All 9 Lines | static int uv_select_similar_island_exec(bContext *C, wmOperator *op) | ||||
| ListBase *island_list_ptr = MEM_callocN(sizeof(*island_list_ptr) * objects_len, __func__); | ListBase *island_list_ptr = MEM_callocN(sizeof(*island_list_ptr) * objects_len, __func__); | ||||
| int island_list_len = 0; | int island_list_len = 0; | ||||
| const bool face_selected = !(scene->toolsettings->uv_flag & UV_SYNC_SELECTION); | const bool face_selected = !(scene->toolsettings->uv_flag & UV_SYNC_SELECTION); | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| Object *obedit = objects[ob_index]; | Object *obedit = objects[ob_index]; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | ||||
| if (cd_loop_uv_offset == -1) { | if (offsets.uv == -1) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| float aspect_y = 1.0f; /* Placeholder value, aspect doesn't change connectivity. */ | float aspect_y = 1.0f; /* Placeholder value, aspect doesn't change connectivity. */ | ||||
| island_list_len += bm_mesh_calc_uv_islands(scene, | island_list_len += bm_mesh_calc_uv_islands( | ||||
| em->bm, | scene, em->bm, &island_list_ptr[ob_index], face_selected, false, false, aspect_y, offsets); | ||||
| &island_list_ptr[ob_index], | |||||
| face_selected, | |||||
| false, | |||||
| false, | |||||
| aspect_y, | |||||
| cd_loop_uv_offset); | |||||
| } | } | ||||
| struct FaceIsland **island_array = MEM_callocN(sizeof(*island_array) * island_list_len, | struct FaceIsland **island_array = MEM_callocN(sizeof(*island_array) * island_list_len, | ||||
| __func__); | __func__); | ||||
| int tree_index = 0; | int tree_index = 0; | ||||
| KDTree_1d *tree_1d = BLI_kdtree_1d_new(island_list_len); | KDTree_1d *tree_1d = BLI_kdtree_1d_new(island_list_len); | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| Object *obedit = objects[ob_index]; | Object *obedit = objects[ob_index]; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| if (cd_loop_uv_offset == -1) { | if (cd_loop_uv_offset == -1) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| float ob_m3[3][3]; | float ob_m3[3][3]; | ||||
| copy_m3_m4(ob_m3, obedit->object_to_world); | copy_m3_m4(ob_m3, obedit->object_to_world); | ||||
| int index; | int index; | ||||
| LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list_ptr[ob_index], index) { | LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list_ptr[ob_index], index) { | ||||
| island_array[index] = island; | island_array[index] = island; | ||||
| if (!uv_island_selected(scene, island)) { | if (!uv_island_selected(scene, island)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| float needle = get_uv_island_needle(type, island, ob_m3, cd_loop_uv_offset); | float needle = get_uv_island_needle(type, island, ob_m3, island->offsets); | ||||
| if (tree_1d) { | if (tree_1d) { | ||||
| BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle); | BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (tree_1d != NULL) { | if (tree_1d != NULL) { | ||||
| BLI_kdtree_1d_deduplicate(tree_1d); | BLI_kdtree_1d_deduplicate(tree_1d); | ||||
| BLI_kdtree_1d_balance(tree_1d); | BLI_kdtree_1d_balance(tree_1d); | ||||
| } | } | ||||
| int tot_island_index = 0; | int tot_island_index = 0; | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| Object *obedit = objects[ob_index]; | Object *obedit = objects[ob_index]; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| if (cd_loop_uv_offset == -1) { | if (cd_loop_uv_offset == -1) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| float ob_m3[3][3]; | float ob_m3[3][3]; | ||||
| copy_m3_m4(ob_m3, obedit->object_to_world); | copy_m3_m4(ob_m3, obedit->object_to_world); | ||||
| bool changed = false; | bool changed = false; | ||||
| int index; | int index; | ||||
| LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list_ptr[ob_index], index) { | LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list_ptr[ob_index], index) { | ||||
| island_array[tot_island_index++] = island; /* To deallocate later. */ | island_array[tot_island_index++] = island; /* To deallocate later. */ | ||||
| if (uv_island_selected(scene, island)) { | if (uv_island_selected(scene, island)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| float needle = get_uv_island_needle(type, island, ob_m3, cd_loop_uv_offset); | float needle = get_uv_island_needle(type, island, ob_m3, island->offsets); | ||||
| bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare); | bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare); | ||||
| if (!select) { | if (!select) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| bool do_history = false; | bool do_history = false; | ||||
| for (int j = 0; j < island->faces_len; j++) { | for (int j = 0; j < island->faces_len; j++) { | ||||
| uvedit_face_select_set( | uvedit_face_select_set( | ||||
| scene, em->bm, island->faces[j], select, do_history, island->cd_loop_uv_offset); | scene, em->bm, island->faces[j], select, do_history, island->offsets); | ||||
| } | } | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| if (changed) { | if (changed) { | ||||
| uv_select_tag_update_for_object(depsgraph, ts, obedit); | uv_select_tag_update_for_object(depsgraph, ts, obedit); | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 115 Lines • ▼ Show 20 Lines | |||||
| /** \name Selected Elements as Arrays (Vertex, Edge & Faces) | /** \name Selected Elements as Arrays (Vertex, Edge & Faces) | ||||
| * | * | ||||
| * These functions return single elements per connected vertex/edge. | * These functions return single elements per connected vertex/edge. | ||||
| * So an edge that has two connected edge loops only assigns one loop in the array. | * So an edge that has two connected edge loops only assigns one loop in the array. | ||||
| * \{ */ | * \{ */ | ||||
| BMFace **ED_uvedit_selected_faces(const Scene *scene, BMesh *bm, int len_max, int *r_faces_len) | BMFace **ED_uvedit_selected_faces(const Scene *scene, BMesh *bm, int len_max, int *r_faces_len) | ||||
| { | { | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(bm); | ||||
| CLAMP_MAX(len_max, bm->totface); | CLAMP_MAX(len_max, bm->totface); | ||||
| int faces_len = 0; | int faces_len = 0; | ||||
| BMFace **faces = MEM_mallocN(sizeof(*faces) * len_max, __func__); | BMFace **faces = MEM_mallocN(sizeof(*faces) * len_max, __func__); | ||||
| BMIter iter; | BMIter iter; | ||||
| BMFace *f; | BMFace *f; | ||||
| BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { | ||||
| if (uvedit_face_visible_test(scene, f)) { | if (uvedit_face_visible_test(scene, f)) { | ||||
| if (uvedit_face_select_test(scene, f, cd_loop_uv_offset)) { | if (uvedit_face_select_test(scene, f, offsets)) { | ||||
| faces[faces_len++] = f; | faces[faces_len++] = f; | ||||
| if (faces_len == len_max) { | if (faces_len == len_max) { | ||||
| goto finally; | goto finally; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| finally: | finally: | ||||
| *r_faces_len = faces_len; | *r_faces_len = faces_len; | ||||
| if (faces_len != len_max) { | if (faces_len != len_max) { | ||||
| faces = MEM_reallocN(faces, sizeof(*faces) * faces_len); | faces = MEM_reallocN(faces, sizeof(*faces) * faces_len); | ||||
| } | } | ||||
| return faces; | return faces; | ||||
| } | } | ||||
| BMLoop **ED_uvedit_selected_edges(const Scene *scene, BMesh *bm, int len_max, int *r_edges_len) | BMLoop **ED_uvedit_selected_edges(const Scene *scene, BMesh *bm, int len_max, int *r_edges_len) | ||||
| { | { | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(bm); | ||||
| BLI_assert(offsets.uv >= 0); | |||||
| CLAMP_MAX(len_max, bm->totloop); | CLAMP_MAX(len_max, bm->totloop); | ||||
| int edges_len = 0; | int edges_len = 0; | ||||
| BMLoop **edges = MEM_mallocN(sizeof(*edges) * len_max, __func__); | BMLoop **edges = MEM_mallocN(sizeof(*edges) * len_max, __func__); | ||||
| BMIter iter; | BMIter iter; | ||||
| BMFace *f; | BMFace *f; | ||||
| /* Clear tag. */ | /* Clear tag. */ | ||||
| BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { | ||||
| BMIter liter; | BMIter liter; | ||||
| BMLoop *l_iter; | BMLoop *l_iter; | ||||
| BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) { | ||||
| BM_elem_flag_disable(l_iter, BM_ELEM_TAG); | BM_elem_flag_disable(l_iter, BM_ELEM_TAG); | ||||
| } | } | ||||
| } | } | ||||
| BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { | ||||
| if (uvedit_face_visible_test(scene, f)) { | if (uvedit_face_visible_test(scene, f)) { | ||||
| BMIter liter; | BMIter liter; | ||||
| BMLoop *l_iter; | BMLoop *l_iter; | ||||
| BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) { | ||||
| if (!BM_elem_flag_test(l_iter, BM_ELEM_TAG)) { | if (!BM_elem_flag_test(l_iter, BM_ELEM_TAG)) { | ||||
| if (uvedit_edge_select_test(scene, l_iter, cd_loop_uv_offset)) { | if (uvedit_edge_select_test(scene, l_iter, offsets)) { | ||||
| BM_elem_flag_enable(l_iter, BM_ELEM_TAG); | BM_elem_flag_enable(l_iter, BM_ELEM_TAG); | ||||
| edges[edges_len++] = l_iter; | edges[edges_len++] = l_iter; | ||||
| if (edges_len == len_max) { | if (edges_len == len_max) { | ||||
| goto finally; | goto finally; | ||||
| } | } | ||||
| /* Tag other connected loops so we don't consider them separate edges. */ | /* Tag other connected loops so we don't consider them separate edges. */ | ||||
| if (l_iter != l_iter->radial_next) { | if (l_iter != l_iter->radial_next) { | ||||
| BMLoop *l_radial_iter = l_iter->radial_next; | BMLoop *l_radial_iter = l_iter->radial_next; | ||||
| do { | do { | ||||
| if (BM_loop_uv_share_edge_check(l_iter, l_radial_iter, cd_loop_uv_offset)) { | if (BM_loop_uv_share_edge_check(l_iter, l_radial_iter, offsets.uv)) { | ||||
| BM_elem_flag_enable(l_radial_iter, BM_ELEM_TAG); | BM_elem_flag_enable(l_radial_iter, BM_ELEM_TAG); | ||||
| } | } | ||||
| } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter); | } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| finally: | finally: | ||||
| *r_edges_len = edges_len; | *r_edges_len = edges_len; | ||||
| if (edges_len != len_max) { | if (edges_len != len_max) { | ||||
| edges = MEM_reallocN(edges, sizeof(*edges) * edges_len); | edges = MEM_reallocN(edges, sizeof(*edges) * edges_len); | ||||
| } | } | ||||
| return edges; | return edges; | ||||
| } | } | ||||
| BMLoop **ED_uvedit_selected_verts(const Scene *scene, BMesh *bm, int len_max, int *r_verts_len) | BMLoop **ED_uvedit_selected_verts(const Scene *scene, BMesh *bm, int len_max, int *r_verts_len) | ||||
| { | { | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(bm); | ||||
| BLI_assert(offsets.select_vert >= 0); | |||||
| BLI_assert(offsets.uv >= 0); | |||||
| CLAMP_MAX(len_max, bm->totloop); | CLAMP_MAX(len_max, bm->totloop); | ||||
| int verts_len = 0; | int verts_len = 0; | ||||
| BMLoop **verts = MEM_mallocN(sizeof(*verts) * len_max, __func__); | BMLoop **verts = MEM_mallocN(sizeof(*verts) * len_max, __func__); | ||||
| BMIter iter; | BMIter iter; | ||||
| BMFace *f; | BMFace *f; | ||||
| /* Clear tag. */ | /* Clear tag. */ | ||||
| BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { | ||||
| BMIter liter; | BMIter liter; | ||||
| BMLoop *l_iter; | BMLoop *l_iter; | ||||
| BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) { | ||||
| BM_elem_flag_disable(l_iter, BM_ELEM_TAG); | BM_elem_flag_disable(l_iter, BM_ELEM_TAG); | ||||
| } | } | ||||
| } | } | ||||
| BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { | ||||
| if (uvedit_face_visible_test(scene, f)) { | if (uvedit_face_visible_test(scene, f)) { | ||||
| BMIter liter; | BMIter liter; | ||||
| BMLoop *l_iter; | BMLoop *l_iter; | ||||
| BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) { | ||||
| if (!BM_elem_flag_test(l_iter, BM_ELEM_TAG)) { | if (!BM_elem_flag_test(l_iter, BM_ELEM_TAG)) { | ||||
| const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset); | if (BM_ELEM_CD_GET_BOOL(l_iter, offsets.select_vert)) { | ||||
| if (luv->flag & MLOOPUV_VERTSEL) { | |||||
| BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG); | BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG); | ||||
| verts[verts_len++] = l_iter; | verts[verts_len++] = l_iter; | ||||
| if (verts_len == len_max) { | if (verts_len == len_max) { | ||||
| goto finally; | goto finally; | ||||
| } | } | ||||
| /* Tag other connected loops so we don't consider them separate vertices. */ | /* Tag other connected loops so we don't consider them separate vertices. */ | ||||
| BMIter liter_disk; | BMIter liter_disk; | ||||
| BMLoop *l_disk_iter; | BMLoop *l_disk_iter; | ||||
| BM_ITER_ELEM (l_disk_iter, &liter_disk, l_iter->v, BM_LOOPS_OF_VERT) { | BM_ITER_ELEM (l_disk_iter, &liter_disk, l_iter->v, BM_LOOPS_OF_VERT) { | ||||
| if (BM_loop_uv_share_vert_check(l_iter, l_disk_iter, cd_loop_uv_offset)) { | if (BM_loop_uv_share_vert_check(l_iter, l_disk_iter, offsets.uv)) { | ||||
| BM_elem_flag_enable(l_disk_iter, BM_ELEM_TAG); | BM_elem_flag_enable(l_disk_iter, BM_ELEM_TAG); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| Show All 13 Lines | |||||
| * \{ */ | * \{ */ | ||||
| /** Deselects UVs that are not part of a complete island selection. | /** Deselects UVs that are not part of a complete island selection. | ||||
| * | * | ||||
| * Use only when sync select disabled. | * Use only when sync select disabled. | ||||
| */ | */ | ||||
| static void uv_isolate_selected_islands(const Scene *scene, | static void uv_isolate_selected_islands(const Scene *scene, | ||||
| BMEditMesh *em, | BMEditMesh *em, | ||||
| const int cd_loop_uv_offset) | const BMUVOffsets offsets) | ||||
| { | { | ||||
| BLI_assert((scene->toolsettings->uv_flag & UV_SYNC_SELECTION) == 0); | BLI_assert((scene->toolsettings->uv_flag & UV_SYNC_SELECTION) == 0); | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| UvElementMap *elementmap = BM_uv_element_map_create(em->bm, scene, false, false, true, true); | UvElementMap *elementmap = BM_uv_element_map_create(em->bm, scene, false, false, true, true); | ||||
| if (elementmap == NULL) { | if (elementmap == NULL) { | ||||
| return; | return; | ||||
| } | } | ||||
| BLI_assert(offsets.select_vert >= 0); | |||||
| BLI_assert(offsets.select_edge >= 0); | |||||
| int num_islands = elementmap->total_islands; | int num_islands = elementmap->total_islands; | ||||
| /* Boolean array that tells if island with index i is completely selected or not. */ | /* Boolean array that tells if island with index i is completely selected or not. */ | ||||
| bool *is_island_not_selected = MEM_callocN(sizeof(bool) * (num_islands), __func__); | bool *is_island_not_selected = MEM_callocN(sizeof(bool) * (num_islands), __func__); | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| BMLoop *l; | BMLoop *l; | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| BM_elem_flag_disable(efa, BM_ELEM_TAG); | BM_elem_flag_disable(efa, BM_ELEM_TAG); | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_elem_flag_enable(efa, BM_ELEM_TAG); | BM_elem_flag_enable(efa, BM_ELEM_TAG); | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| if (!uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) { | if (!uvedit_edge_select_test(scene, l, offsets)) { | ||||
| UvElement *element = BM_uv_element_get(elementmap, efa, l); | UvElement *element = BM_uv_element_get(elementmap, efa, l); | ||||
| is_island_not_selected[element->island] = true; | is_island_not_selected[element->island] = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| BMLoop *l; | BMLoop *l; | ||||
| if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) { | if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| UvElement *element = BM_uv_element_get(elementmap, efa, l); | UvElement *element = BM_uv_element_get(elementmap, efa, l); | ||||
| /* Deselect all elements of islands which are not completely selected. */ | /* Deselect all elements of islands which are not completely selected. */ | ||||
| if (is_island_not_selected[element->island] == true) { | if (is_island_not_selected[element->island] == true) { | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | BM_ELEM_CD_SET_BOOL(l, offsets.select_vert, false); | ||||
| luv->flag &= ~(MLOOPUV_VERTSEL | MLOOPUV_EDGESEL); | BM_ELEM_CD_SET_BOOL(l, offsets.select_edge, false); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| BM_uv_element_map_free(elementmap); | BM_uv_element_map_free(elementmap); | ||||
| MEM_freeN(is_island_not_selected); | MEM_freeN(is_island_not_selected); | ||||
| } | } | ||||
| void ED_uvedit_selectmode_clean(const Scene *scene, Object *obedit) | void ED_uvedit_selectmode_clean(const Scene *scene, Object *obedit) | ||||
| { | { | ||||
| const ToolSettings *ts = scene->toolsettings; | const ToolSettings *ts = scene->toolsettings; | ||||
| BLI_assert((ts->uv_flag & UV_SYNC_SELECTION) == 0); | BLI_assert((ts->uv_flag & UV_SYNC_SELECTION) == 0); | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| char sticky = ts->uv_sticky; | char sticky = ts->uv_sticky; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const char *active_uv_name = CustomData_get_active_layer_name(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| BM_uv_map_ensure_vert_select_attr(em->bm, active_uv_name); | |||||
| BM_uv_map_ensure_edge_select_attr(em->bm, active_uv_name); | |||||
| const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | |||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| if (ts->uv_selectmode == UV_SELECT_VERTEX) { | if (ts->uv_selectmode == UV_SELECT_VERTEX) { | ||||
| /* Vertex mode. */ | /* Vertex mode. */ | ||||
| if (sticky != SI_STICKY_DISABLE) { | if (sticky != SI_STICKY_DISABLE) { | ||||
| bm_loop_tags_clear(em->bm); | bm_loop_tags_clear(em->bm); | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { | if (uvedit_uv_select_test(scene, l, offsets)) { | ||||
| BM_elem_flag_enable(l, BM_ELEM_TAG); | BM_elem_flag_enable(l, BM_ELEM_TAG); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| uv_select_flush_from_tag_loop(scene, obedit, true); | uv_select_flush_from_tag_loop(scene, obedit, true); | ||||
| } | } | ||||
| } | } | ||||
| else if (ts->uv_selectmode == UV_SELECT_EDGE) { | else if (ts->uv_selectmode == UV_SELECT_EDGE) { | ||||
| /* Edge mode. */ | /* Edge mode. */ | ||||
| if (sticky != SI_STICKY_DISABLE) { | if (sticky != SI_STICKY_DISABLE) { | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| if (uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) { | if (uvedit_edge_select_test(scene, l, offsets)) { | ||||
| uvedit_edge_select_set_noflush(scene, l, true, sticky, cd_loop_uv_offset); | uvedit_edge_select_set_noflush(scene, l, true, sticky, offsets); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| uv_select_flush_from_loop_edge_flag(scene, em); | uv_select_flush_from_loop_edge_flag(scene, em); | ||||
| } | } | ||||
| else if (ts->uv_selectmode == UV_SELECT_FACE) { | else if (ts->uv_selectmode == UV_SELECT_FACE) { | ||||
| /* Face mode. */ | /* Face mode. */ | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| BM_elem_flag_disable(efa, BM_ELEM_TAG); | BM_elem_flag_disable(efa, BM_ELEM_TAG); | ||||
| if (uvedit_face_visible_test(scene, efa)) { | if (uvedit_face_visible_test(scene, efa)) { | ||||
| if (uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { | if (uvedit_face_select_test(scene, efa, offsets)) { | ||||
| BM_elem_flag_enable(efa, BM_ELEM_TAG); | BM_elem_flag_enable(efa, BM_ELEM_TAG); | ||||
| } | } | ||||
| uvedit_face_select_set(scene, em->bm, efa, false, false, cd_loop_uv_offset); | uvedit_face_select_set(scene, em->bm, efa, false, false, offsets); | ||||
| } | } | ||||
| } | } | ||||
| uv_select_flush_from_tag_face(scene, obedit, true); | uv_select_flush_from_tag_face(scene, obedit, true); | ||||
| } | } | ||||
| else if (ts->uv_selectmode == UV_SELECT_ISLAND) { | else if (ts->uv_selectmode == UV_SELECT_ISLAND) { | ||||
| /* Island mode. */ | /* Island mode. */ | ||||
| uv_isolate_selected_islands(scene, em, cd_loop_uv_offset); | uv_isolate_selected_islands(scene, em, offsets); | ||||
| } | } | ||||
| ED_uvedit_selectmode_flush(scene, em); | ED_uvedit_selectmode_flush(scene, em); | ||||
| } | } | ||||
| void ED_uvedit_selectmode_clean_multi(bContext *C) | void ED_uvedit_selectmode_clean_multi(bContext *C) | ||||
| { | { | ||||
| Scene *scene = CTX_data_scene(C); | Scene *scene = CTX_data_scene(C); | ||||
| ▲ Show 20 Lines • Show All 80 Lines • Show Last 20 Lines | |||||
Do we need to add?