Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/mesh/editmesh_select.cc
- This file was moved from source/blender/editors/mesh/editmesh_select.c.
| /* SPDX-License-Identifier: GPL-2.0-or-later | /* SPDX-License-Identifier: GPL-2.0-or-later | ||||
| * Copyright 2004 Blender Foundation. All rights reserved. */ | * Copyright 2004 Blender Foundation. All rights reserved. */ | ||||
| /** \file | /** \file | ||||
| * \ingroup edmesh | * \ingroup edmesh | ||||
| */ | */ | ||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "BLI_array.h" | |||||
| #include "BLI_bitmap.h" | #include "BLI_bitmap.h" | ||||
| #include "BLI_heap.h" | #include "BLI_heap.h" | ||||
| #include "BLI_linklist.h" | #include "BLI_linklist.h" | ||||
| #include "BLI_linklist_stack.h" | |||||
| #include "BLI_listbase.h" | #include "BLI_listbase.h" | ||||
| #include "BLI_math.h" | #include "BLI_math.h" | ||||
| #include "BLI_math_bits.h" | #include "BLI_math_bits.h" | ||||
| #include "BLI_rand.h" | #include "BLI_rand.h" | ||||
| #include "BLI_string.h" | #include "BLI_string.h" | ||||
| #include "BLI_utildefines_stack.h" | #include "BLI_utildefines_stack.h" | ||||
| #include "BLI_vector.hh" | |||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||
| #include "BKE_customdata.h" | #include "BKE_customdata.h" | ||||
| #include "BKE_deform.h" | #include "BKE_deform.h" | ||||
| #include "BKE_editmesh.h" | #include "BKE_editmesh.h" | ||||
| #include "BKE_layer.h" | #include "BKE_layer.h" | ||||
| #include "BKE_report.h" | #include "BKE_report.h" | ||||
| ▲ Show 20 Lines • Show All 148 Lines • ▼ Show 20 Lines | switch (elem_type) { | ||||
| case SCE_SELECT_FACE: | case SCE_SELECT_FACE: | ||||
| return (BMElem *)BM_face_at_index_find_or_table(em->bm, elem_id); | return (BMElem *)BM_face_at_index_find_or_table(em->bm, elem_id); | ||||
| case SCE_SELECT_EDGE: | case SCE_SELECT_EDGE: | ||||
| return (BMElem *)BM_edge_at_index_find_or_table(em->bm, elem_id); | return (BMElem *)BM_edge_at_index_find_or_table(em->bm, elem_id); | ||||
| case SCE_SELECT_VERTEX: | case SCE_SELECT_VERTEX: | ||||
| return (BMElem *)BM_vert_at_index_find_or_table(em->bm, elem_id); | return (BMElem *)BM_vert_at_index_find_or_table(em->bm, elem_id); | ||||
| default: | default: | ||||
| BLI_assert(0); | BLI_assert(0); | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Find Nearest Vert/Edge/Face | /** \name Find Nearest Vert/Edge/Face | ||||
| * | * | ||||
| * \note Screen-space manhattan distances are used here, | * \note Screen-space manhattan distances are used here, | ||||
| Show All 15 Lines | |||||
| }; | }; | ||||
| struct NearestVertUserData { | struct NearestVertUserData { | ||||
| float mval_fl[2]; | float mval_fl[2]; | ||||
| bool use_select_bias; | bool use_select_bias; | ||||
| bool use_cycle; | bool use_cycle; | ||||
| int cycle_index_prev; | int cycle_index_prev; | ||||
| struct NearestVertUserData_Hit hit; | NearestVertUserData_Hit hit; | ||||
| struct NearestVertUserData_Hit hit_cycle; | NearestVertUserData_Hit hit_cycle; | ||||
| }; | }; | ||||
| static void findnearestvert__doClosest(void *userData, | static void findnearestvert__doClosest(void *userData, | ||||
| BMVert *eve, | BMVert *eve, | ||||
| const float screen_co[2], | const float screen_co[2], | ||||
| int index) | int index) | ||||
| { | { | ||||
| struct NearestVertUserData *data = userData; | NearestVertUserData *data = static_cast<NearestVertUserData *>(userData); | ||||
| float dist_test, dist_test_bias; | float dist_test, dist_test_bias; | ||||
| dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co); | dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co); | ||||
| if (data->use_select_bias && BM_elem_flag_test(eve, BM_ELEM_SELECT)) { | if (data->use_select_bias && BM_elem_flag_test(eve, BM_ELEM_SELECT)) { | ||||
| dist_test_bias += FIND_NEAR_SELECT_BIAS; | dist_test_bias += FIND_NEAR_SELECT_BIAS; | ||||
| } | } | ||||
| if (dist_test_bias < data->hit.dist_bias) { | if (dist_test_bias < data->hit.dist_bias) { | ||||
| data->hit.dist_bias = dist_test_bias; | data->hit.dist_bias = dist_test_bias; | ||||
| data->hit.dist = dist_test; | data->hit.dist = dist_test; | ||||
| data->hit.index = index; | data->hit.index = index; | ||||
| data->hit.vert = eve; | data->hit.vert = eve; | ||||
| } | } | ||||
| if (data->use_cycle) { | if (data->use_cycle) { | ||||
| if ((data->hit_cycle.vert == NULL) && (index > data->cycle_index_prev) && | if ((data->hit_cycle.vert == nullptr) && (index > data->cycle_index_prev) && | ||||
| (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN)) { | (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN)) { | ||||
| data->hit_cycle.dist_bias = dist_test_bias; | data->hit_cycle.dist_bias = dist_test_bias; | ||||
| data->hit_cycle.dist = dist_test; | data->hit_cycle.dist = dist_test; | ||||
| data->hit_cycle.index = index; | data->hit_cycle.index = index; | ||||
| data->hit_cycle.vert = eve; | data->hit_cycle.vert = eve; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| Show All 9 Lines | BMVert *EDBM_vert_find_nearest_ex(ViewContext *vc, | ||||
| uint base_index = 0; | uint base_index = 0; | ||||
| if (!XRAY_FLAG_ENABLED(vc->v3d)) { | if (!XRAY_FLAG_ENABLED(vc->v3d)) { | ||||
| uint dist_px_manhattan_test = (uint)ED_view3d_backbuf_sample_size_clamp(vc->region, | uint dist_px_manhattan_test = (uint)ED_view3d_backbuf_sample_size_clamp(vc->region, | ||||
| *dist_px_manhattan_p); | *dist_px_manhattan_p); | ||||
| uint index; | uint index; | ||||
| BMVert *eve; | BMVert *eve; | ||||
| /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */ | /* No after-queue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */ | ||||
| { | { | ||||
| DRW_select_buffer_context_create(bases, bases_len, SCE_SELECT_VERTEX); | DRW_select_buffer_context_create(bases, bases_len, SCE_SELECT_VERTEX); | ||||
| index = DRW_select_buffer_find_nearest_to_point( | index = DRW_select_buffer_find_nearest_to_point( | ||||
| vc->depsgraph, vc->region, vc->v3d, vc->mval, 1, UINT_MAX, &dist_px_manhattan_test); | vc->depsgraph, vc->region, vc->v3d, vc->mval, 1, UINT_MAX, &dist_px_manhattan_test); | ||||
| if (index) { | if (index) { | ||||
| eve = (BMVert *)edbm_select_id_bm_elem_get(bases, index, &base_index); | eve = (BMVert *)edbm_select_id_bm_elem_get(bases, index, &base_index); | ||||
| } | } | ||||
| else { | else { | ||||
| eve = NULL; | eve = nullptr; | ||||
| } | } | ||||
| } | } | ||||
| if (eve) { | if (eve) { | ||||
| if (dist_px_manhattan_test < *dist_px_manhattan_p) { | if (dist_px_manhattan_test < *dist_px_manhattan_p) { | ||||
| if (r_base_index) { | if (r_base_index) { | ||||
| *r_base_index = base_index; | *r_base_index = base_index; | ||||
| } | } | ||||
| *dist_px_manhattan_p = dist_px_manhattan_test; | *dist_px_manhattan_p = dist_px_manhattan_test; | ||||
| return eve; | return eve; | ||||
| } | } | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| struct NearestVertUserData data = {{0}}; | NearestVertUserData data = {{0}}; | ||||
| const struct NearestVertUserData_Hit *hit = NULL; | const NearestVertUserData_Hit *hit = nullptr; | ||||
| const eV3DProjTest clip_flag = RV3D_CLIPPING_ENABLED(vc->v3d, vc->rv3d) ? | const eV3DProjTest clip_flag = RV3D_CLIPPING_ENABLED(vc->v3d, vc->rv3d) ? | ||||
| V3D_PROJ_TEST_CLIP_DEFAULT : | V3D_PROJ_TEST_CLIP_DEFAULT : | ||||
| V3D_PROJ_TEST_CLIP_DEFAULT & ~V3D_PROJ_TEST_CLIP_BB; | V3D_PROJ_TEST_CLIP_DEFAULT & ~V3D_PROJ_TEST_CLIP_BB; | ||||
| BMesh *prev_select_bm = NULL; | BMesh *prev_select_bm = nullptr; | ||||
| static struct { | static struct { | ||||
| int index; | int index; | ||||
| const BMVert *elem; | const BMVert *elem; | ||||
| const BMesh *bm; | const BMesh *bm; | ||||
| } prev_select = {0}; | } prev_select = {0}; | ||||
| data.mval_fl[0] = vc->mval[0]; | data.mval_fl[0] = vc->mval[0]; | ||||
| Show All 26 Lines | if (hit->dist < *dist_px_manhattan_p) { | ||||
| if (r_base_index) { | if (r_base_index) { | ||||
| *r_base_index = base_index; | *r_base_index = base_index; | ||||
| } | } | ||||
| *dist_px_manhattan_p = hit->dist; | *dist_px_manhattan_p = hit->dist; | ||||
| prev_select_bm = vc->em->bm; | prev_select_bm = vc->em->bm; | ||||
| } | } | ||||
| } | } | ||||
| if (hit == NULL) { | if (hit == nullptr) { | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| prev_select.index = hit->index; | prev_select.index = hit->index; | ||||
| prev_select.elem = hit->vert; | prev_select.elem = hit->vert; | ||||
| prev_select.bm = prev_select_bm; | prev_select.bm = prev_select_bm; | ||||
| return hit->vert; | return hit->vert; | ||||
| } | } | ||||
| BMVert *EDBM_vert_find_nearest(ViewContext *vc, float *dist_px_manhattan_p) | BMVert *EDBM_vert_find_nearest(ViewContext *vc, float *dist_px_manhattan_p) | ||||
| { | { | ||||
| BKE_view_layer_synced_ensure(vc->scene, vc->view_layer); | BKE_view_layer_synced_ensure(vc->scene, vc->view_layer); | ||||
| Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact); | Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact); | ||||
| return EDBM_vert_find_nearest_ex(vc, dist_px_manhattan_p, false, false, &base, 1, NULL); | return EDBM_vert_find_nearest_ex(vc, dist_px_manhattan_p, false, false, &base, 1, nullptr); | ||||
| } | } | ||||
| /* find the distance to the edge we already have */ | /* find the distance to the edge we already have */ | ||||
| struct NearestEdgeUserData_ZBuf { | struct NearestEdgeUserData_ZBuf { | ||||
| float mval_fl[2]; | float mval_fl[2]; | ||||
| float dist; | float dist; | ||||
| const BMEdge *edge_test; | const BMEdge *edge_test; | ||||
| }; | }; | ||||
| static void find_nearest_edge_center__doZBuf(void *userData, | static void find_nearest_edge_center__doZBuf(void *userData, | ||||
| BMEdge *eed, | BMEdge *eed, | ||||
| const float screen_co_a[2], | const float screen_co_a[2], | ||||
| const float screen_co_b[2], | const float screen_co_b[2], | ||||
| int UNUSED(index)) | int UNUSED(index)) | ||||
| { | { | ||||
| struct NearestEdgeUserData_ZBuf *data = userData; | NearestEdgeUserData_ZBuf *data = static_cast<NearestEdgeUserData_ZBuf *>(userData); | ||||
| if (eed == data->edge_test) { | if (eed == data->edge_test) { | ||||
| float dist_test; | float dist_test; | ||||
| float screen_co_mid[2]; | float screen_co_mid[2]; | ||||
| mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b); | mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b); | ||||
| dist_test = len_manhattan_v2v2(data->mval_fl, screen_co_mid); | dist_test = len_manhattan_v2v2(data->mval_fl, screen_co_mid); | ||||
| Show All 16 Lines | |||||
| struct NearestEdgeUserData { | struct NearestEdgeUserData { | ||||
| ViewContext vc; | ViewContext vc; | ||||
| float mval_fl[2]; | float mval_fl[2]; | ||||
| bool use_select_bias; | bool use_select_bias; | ||||
| bool use_cycle; | bool use_cycle; | ||||
| int cycle_index_prev; | int cycle_index_prev; | ||||
| struct NearestEdgeUserData_Hit hit; | NearestEdgeUserData_Hit hit; | ||||
| struct NearestEdgeUserData_Hit hit_cycle; | NearestEdgeUserData_Hit hit_cycle; | ||||
| }; | }; | ||||
| /* NOTE: uses v3d, so needs active 3d window. */ | /* NOTE: uses v3d, so needs active 3d window. */ | ||||
| static void find_nearest_edge__doClosest( | static void find_nearest_edge__doClosest( | ||||
| void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) | void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) | ||||
| { | { | ||||
| struct NearestEdgeUserData *data = userData; | NearestEdgeUserData *data = static_cast<NearestEdgeUserData *>(userData); | ||||
| float dist_test, dist_test_bias; | float dist_test, dist_test_bias; | ||||
| float fac = line_point_factor_v2(data->mval_fl, screen_co_a, screen_co_b); | float fac = line_point_factor_v2(data->mval_fl, screen_co_a, screen_co_b); | ||||
| float screen_co[2]; | float screen_co[2]; | ||||
| if (fac <= 0.0f) { | if (fac <= 0.0f) { | ||||
| fac = 0.0f; | fac = 0.0f; | ||||
| copy_v2_v2(screen_co, screen_co_a); | copy_v2_v2(screen_co, screen_co_a); | ||||
| Show All 29 Lines | if (dist_test_bias < data->hit.dist_bias) { | ||||
| data->hit.index = index; | data->hit.index = index; | ||||
| data->hit.edge = eed; | data->hit.edge = eed; | ||||
| mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b); | mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b); | ||||
| data->hit.dist_center_px_manhattan = len_manhattan_v2v2(data->mval_fl, screen_co_mid); | data->hit.dist_center_px_manhattan = len_manhattan_v2v2(data->mval_fl, screen_co_mid); | ||||
| } | } | ||||
| if (data->use_cycle) { | if (data->use_cycle) { | ||||
| if ((data->hit_cycle.edge == NULL) && (index > data->cycle_index_prev) && | if ((data->hit_cycle.edge == nullptr) && (index > data->cycle_index_prev) && | ||||
| (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN)) { | (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN)) { | ||||
| float screen_co_mid[2]; | float screen_co_mid[2]; | ||||
| data->hit_cycle.dist_bias = dist_test_bias; | data->hit_cycle.dist_bias = dist_test_bias; | ||||
| data->hit_cycle.dist = dist_test; | data->hit_cycle.dist = dist_test; | ||||
| data->hit_cycle.index = index; | data->hit_cycle.index = index; | ||||
| data->hit_cycle.edge = eed; | data->hit_cycle.edge = eed; | ||||
| Show All 16 Lines | BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc, | ||||
| uint base_index = 0; | uint base_index = 0; | ||||
| if (!XRAY_FLAG_ENABLED(vc->v3d)) { | if (!XRAY_FLAG_ENABLED(vc->v3d)) { | ||||
| uint dist_px_manhattan_test = (uint)ED_view3d_backbuf_sample_size_clamp(vc->region, | uint dist_px_manhattan_test = (uint)ED_view3d_backbuf_sample_size_clamp(vc->region, | ||||
| *dist_px_manhattan_p); | *dist_px_manhattan_p); | ||||
| uint index; | uint index; | ||||
| BMEdge *eed; | BMEdge *eed; | ||||
| /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */ | /* No after-queue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */ | ||||
| { | { | ||||
| DRW_select_buffer_context_create(bases, bases_len, SCE_SELECT_EDGE); | DRW_select_buffer_context_create(bases, bases_len, SCE_SELECT_EDGE); | ||||
| index = DRW_select_buffer_find_nearest_to_point( | index = DRW_select_buffer_find_nearest_to_point( | ||||
| vc->depsgraph, vc->region, vc->v3d, vc->mval, 1, UINT_MAX, &dist_px_manhattan_test); | vc->depsgraph, vc->region, vc->v3d, vc->mval, 1, UINT_MAX, &dist_px_manhattan_test); | ||||
| if (index) { | if (index) { | ||||
| eed = (BMEdge *)edbm_select_id_bm_elem_get(bases, index, &base_index); | eed = (BMEdge *)edbm_select_id_bm_elem_get(bases, index, &base_index); | ||||
| } | } | ||||
| else { | else { | ||||
| eed = NULL; | eed = nullptr; | ||||
| } | } | ||||
| } | } | ||||
| if (r_eed_zbuf) { | if (r_eed_zbuf) { | ||||
| *r_eed_zbuf = eed; | *r_eed_zbuf = eed; | ||||
| } | } | ||||
| /* exception for faces (verts don't need this) */ | /* exception for faces (verts don't need this) */ | ||||
| if (r_dist_center_px_manhattan && eed) { | if (r_dist_center_px_manhattan && eed) { | ||||
| struct NearestEdgeUserData_ZBuf data; | NearestEdgeUserData_ZBuf data; | ||||
| data.mval_fl[0] = vc->mval[0]; | data.mval_fl[0] = vc->mval[0]; | ||||
| data.mval_fl[1] = vc->mval[1]; | data.mval_fl[1] = vc->mval[1]; | ||||
| data.dist = FLT_MAX; | data.dist = FLT_MAX; | ||||
| data.edge_test = eed; | data.edge_test = eed; | ||||
| ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); | ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); | ||||
| Show All 10 Lines | if (eed) { | ||||
| if (dist_px_manhattan_test < *dist_px_manhattan_p) { | if (dist_px_manhattan_test < *dist_px_manhattan_p) { | ||||
| if (r_base_index) { | if (r_base_index) { | ||||
| *r_base_index = base_index; | *r_base_index = base_index; | ||||
| } | } | ||||
| *dist_px_manhattan_p = dist_px_manhattan_test; | *dist_px_manhattan_p = dist_px_manhattan_test; | ||||
| return eed; | return eed; | ||||
| } | } | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| struct NearestEdgeUserData data = {{0}}; | NearestEdgeUserData data = {{0}}; | ||||
| const struct NearestEdgeUserData_Hit *hit = NULL; | const NearestEdgeUserData_Hit *hit = nullptr; | ||||
| /* interpolate along the edge before doing a clipping plane test */ | /* interpolate along the edge before doing a clipping plane test */ | ||||
| const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT & ~V3D_PROJ_TEST_CLIP_BB; | const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT & ~V3D_PROJ_TEST_CLIP_BB; | ||||
| BMesh *prev_select_bm = NULL; | BMesh *prev_select_bm = nullptr; | ||||
| static struct { | static struct { | ||||
| int index; | int index; | ||||
| const BMEdge *elem; | const BMEdge *elem; | ||||
| const BMesh *bm; | const BMesh *bm; | ||||
| } prev_select = {0}; | } prev_select = {0}; | ||||
| data.vc = *vc; | data.vc = *vc; | ||||
| Show All 28 Lines | if (hit->dist < *dist_px_manhattan_p) { | ||||
| if (r_base_index) { | if (r_base_index) { | ||||
| *r_base_index = base_index; | *r_base_index = base_index; | ||||
| } | } | ||||
| *dist_px_manhattan_p = hit->dist; | *dist_px_manhattan_p = hit->dist; | ||||
| prev_select_bm = vc->em->bm; | prev_select_bm = vc->em->bm; | ||||
| } | } | ||||
| } | } | ||||
| if (hit == NULL) { | if (hit == nullptr) { | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| if (r_dist_center_px_manhattan) { | if (r_dist_center_px_manhattan) { | ||||
| *r_dist_center_px_manhattan = hit->dist_center_px_manhattan; | *r_dist_center_px_manhattan = hit->dist_center_px_manhattan; | ||||
| } | } | ||||
| prev_select.index = hit->index; | prev_select.index = hit->index; | ||||
| prev_select.elem = hit->edge; | prev_select.elem = hit->edge; | ||||
| prev_select.bm = prev_select_bm; | prev_select.bm = prev_select_bm; | ||||
| return hit->edge; | return hit->edge; | ||||
| } | } | ||||
| BMEdge *EDBM_edge_find_nearest(ViewContext *vc, float *dist_px_manhattan_p) | BMEdge *EDBM_edge_find_nearest(ViewContext *vc, float *dist_px_manhattan_p) | ||||
| { | { | ||||
| BKE_view_layer_synced_ensure(vc->scene, vc->view_layer); | BKE_view_layer_synced_ensure(vc->scene, vc->view_layer); | ||||
| Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact); | Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact); | ||||
| return EDBM_edge_find_nearest_ex( | return EDBM_edge_find_nearest_ex( | ||||
| vc, dist_px_manhattan_p, NULL, false, false, NULL, &base, 1, NULL); | vc, dist_px_manhattan_p, nullptr, false, false, nullptr, &base, 1, nullptr); | ||||
| } | } | ||||
| /* find the distance to the face we already have */ | /* find the distance to the face we already have */ | ||||
| struct NearestFaceUserData_ZBuf { | struct NearestFaceUserData_ZBuf { | ||||
| float mval_fl[2]; | float mval_fl[2]; | ||||
| float dist_px_manhattan; | float dist_px_manhattan; | ||||
| const BMFace *face_test; | const BMFace *face_test; | ||||
| }; | }; | ||||
| static void find_nearest_face_center__doZBuf(void *userData, | static void find_nearest_face_center__doZBuf(void *userData, | ||||
| BMFace *efa, | BMFace *efa, | ||||
| const float screen_co[2], | const float screen_co[2], | ||||
| int UNUSED(index)) | int UNUSED(index)) | ||||
| { | { | ||||
| struct NearestFaceUserData_ZBuf *data = userData; | NearestFaceUserData_ZBuf *data = static_cast<NearestFaceUserData_ZBuf *>(userData); | ||||
| if (efa == data->face_test) { | if (efa == data->face_test) { | ||||
| const float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co); | const float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co); | ||||
| if (dist_test < data->dist_px_manhattan) { | if (dist_test < data->dist_px_manhattan) { | ||||
| data->dist_px_manhattan = dist_test; | data->dist_px_manhattan = dist_test; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| struct NearestFaceUserData_Hit { | struct NearestFaceUserData_Hit { | ||||
| float dist; | float dist; | ||||
| float dist_bias; | float dist_bias; | ||||
| int index; | int index; | ||||
| BMFace *face; | BMFace *face; | ||||
| }; | }; | ||||
| struct NearestFaceUserData { | struct NearestFaceUserData { | ||||
| float mval_fl[2]; | float mval_fl[2]; | ||||
| bool use_select_bias; | bool use_select_bias; | ||||
| bool use_cycle; | bool use_cycle; | ||||
| int cycle_index_prev; | int cycle_index_prev; | ||||
| struct NearestFaceUserData_Hit hit; | NearestFaceUserData_Hit hit; | ||||
| struct NearestFaceUserData_Hit hit_cycle; | NearestFaceUserData_Hit hit_cycle; | ||||
| }; | }; | ||||
| static void findnearestface__doClosest(void *userData, | static void findnearestface__doClosest(void *userData, | ||||
| BMFace *efa, | BMFace *efa, | ||||
| const float screen_co[2], | const float screen_co[2], | ||||
| int index) | int index) | ||||
| { | { | ||||
| struct NearestFaceUserData *data = userData; | NearestFaceUserData *data = static_cast<NearestFaceUserData *>(userData); | ||||
| float dist_test, dist_test_bias; | float dist_test, dist_test_bias; | ||||
| dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co); | dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co); | ||||
| if (data->use_select_bias && BM_elem_flag_test(efa, BM_ELEM_SELECT)) { | if (data->use_select_bias && BM_elem_flag_test(efa, BM_ELEM_SELECT)) { | ||||
| dist_test_bias += FIND_NEAR_SELECT_BIAS; | dist_test_bias += FIND_NEAR_SELECT_BIAS; | ||||
| } | } | ||||
| if (dist_test_bias < data->hit.dist_bias) { | if (dist_test_bias < data->hit.dist_bias) { | ||||
| data->hit.dist_bias = dist_test_bias; | data->hit.dist_bias = dist_test_bias; | ||||
| data->hit.dist = dist_test; | data->hit.dist = dist_test; | ||||
| data->hit.index = index; | data->hit.index = index; | ||||
| data->hit.face = efa; | data->hit.face = efa; | ||||
| } | } | ||||
| if (data->use_cycle) { | if (data->use_cycle) { | ||||
| if ((data->hit_cycle.face == NULL) && (index > data->cycle_index_prev) && | if ((data->hit_cycle.face == nullptr) && (index > data->cycle_index_prev) && | ||||
| (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN)) { | (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN)) { | ||||
| data->hit_cycle.dist_bias = dist_test_bias; | data->hit_cycle.dist_bias = dist_test_bias; | ||||
| data->hit_cycle.dist = dist_test; | data->hit_cycle.dist = dist_test; | ||||
| data->hit_cycle.index = index; | data->hit_cycle.index = index; | ||||
| data->hit_cycle.face = efa; | data->hit_cycle.face = efa; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| Show All 34 Lines | BMFace *efa; | ||||
| vc->depsgraph, vc->region, vc->v3d, vc->mval, 1, UINT_MAX, &dist_px_manhattan_test); | vc->depsgraph, vc->region, vc->v3d, vc->mval, 1, UINT_MAX, &dist_px_manhattan_test); | ||||
| dist_test = dist_px_manhattan_test; | dist_test = dist_px_manhattan_test; | ||||
| } | } | ||||
| if (index) { | if (index) { | ||||
| efa = (BMFace *)edbm_select_id_bm_elem_get(bases, index, &base_index); | efa = (BMFace *)edbm_select_id_bm_elem_get(bases, index, &base_index); | ||||
| } | } | ||||
| else { | else { | ||||
| efa = NULL; | efa = nullptr; | ||||
| } | } | ||||
| } | } | ||||
| if (r_efa_zbuf) { | if (r_efa_zbuf) { | ||||
| *r_efa_zbuf = efa; | *r_efa_zbuf = efa; | ||||
| } | } | ||||
| /* exception for faces (verts don't need this) */ | /* exception for faces (verts don't need this) */ | ||||
| if (r_dist_center && efa) { | if (r_dist_center && efa) { | ||||
| struct NearestFaceUserData_ZBuf data; | NearestFaceUserData_ZBuf data; | ||||
| data.mval_fl[0] = vc->mval[0]; | data.mval_fl[0] = vc->mval[0]; | ||||
| data.mval_fl[1] = vc->mval[1]; | data.mval_fl[1] = vc->mval[1]; | ||||
| data.dist_px_manhattan = FLT_MAX; | data.dist_px_manhattan = FLT_MAX; | ||||
| data.face_test = efa; | data.face_test = efa; | ||||
| ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); | ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); | ||||
| mesh_foreachScreenFace( | mesh_foreachScreenFace( | ||||
| vc, find_nearest_face_center__doZBuf, &data, V3D_PROJ_TEST_CLIP_DEFAULT); | vc, find_nearest_face_center__doZBuf, &data, V3D_PROJ_TEST_CLIP_DEFAULT); | ||||
| *r_dist_center = data.dist_px_manhattan; | *r_dist_center = data.dist_px_manhattan; | ||||
| } | } | ||||
| /* end exception */ | /* end exception */ | ||||
| if (efa) { | if (efa) { | ||||
| if (dist_test < *dist_px_manhattan_p) { | if (dist_test < *dist_px_manhattan_p) { | ||||
| if (r_base_index) { | if (r_base_index) { | ||||
| *r_base_index = base_index; | *r_base_index = base_index; | ||||
| } | } | ||||
| *dist_px_manhattan_p = dist_test; | *dist_px_manhattan_p = dist_test; | ||||
| return efa; | return efa; | ||||
| } | } | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| struct NearestFaceUserData data = {{0}}; | NearestFaceUserData data = {{0}}; | ||||
| const struct NearestFaceUserData_Hit *hit = NULL; | const NearestFaceUserData_Hit *hit = nullptr; | ||||
| const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT; | const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT; | ||||
| BMesh *prev_select_bm = NULL; | BMesh *prev_select_bm = nullptr; | ||||
| static struct { | static struct { | ||||
| int index; | int index; | ||||
| const BMFace *elem; | const BMFace *elem; | ||||
| const BMesh *bm; | const BMesh *bm; | ||||
| } prev_select = {0}; | } prev_select = {0}; | ||||
| data.mval_fl[0] = vc->mval[0]; | data.mval_fl[0] = vc->mval[0]; | ||||
| Show All 26 Lines | if (hit->dist < *dist_px_manhattan_p) { | ||||
| if (r_base_index) { | if (r_base_index) { | ||||
| *r_base_index = base_index; | *r_base_index = base_index; | ||||
| } | } | ||||
| *dist_px_manhattan_p = hit->dist; | *dist_px_manhattan_p = hit->dist; | ||||
| prev_select_bm = vc->em->bm; | prev_select_bm = vc->em->bm; | ||||
| } | } | ||||
| } | } | ||||
| if (hit == NULL) { | if (hit == nullptr) { | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| if (r_dist_center) { | if (r_dist_center) { | ||||
| *r_dist_center = hit->dist; | *r_dist_center = hit->dist; | ||||
| } | } | ||||
| prev_select.index = hit->index; | prev_select.index = hit->index; | ||||
| prev_select.elem = hit->face; | prev_select.elem = hit->face; | ||||
| prev_select.bm = prev_select_bm; | prev_select.bm = prev_select_bm; | ||||
| return hit->face; | return hit->face; | ||||
| } | } | ||||
| BMFace *EDBM_face_find_nearest(ViewContext *vc, float *dist_px_manhattan_p) | BMFace *EDBM_face_find_nearest(ViewContext *vc, float *dist_px_manhattan_p) | ||||
| { | { | ||||
| BKE_view_layer_synced_ensure(vc->scene, vc->view_layer); | BKE_view_layer_synced_ensure(vc->scene, vc->view_layer); | ||||
| Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact); | Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact); | ||||
| return EDBM_face_find_nearest_ex( | return EDBM_face_find_nearest_ex( | ||||
| vc, dist_px_manhattan_p, NULL, false, false, false, NULL, &base, 1, NULL); | vc, dist_px_manhattan_p, nullptr, false, false, false, nullptr, &base, 1, nullptr); | ||||
| } | } | ||||
| #undef FIND_NEAR_SELECT_BIAS | #undef FIND_NEAR_SELECT_BIAS | ||||
| #undef FIND_NEAR_CYCLE_THRESHOLD_MIN | #undef FIND_NEAR_CYCLE_THRESHOLD_MIN | ||||
| /* best distance based on screen coords. | /* best distance based on screen coords. | ||||
| * use em->selectmode to define how to use | * use em->selectmode to define how to use | ||||
| * selected vertices and edges get disadvantage | * selected vertices and edges get disadvantage | ||||
| Show All 23 Lines | struct { | ||||
| struct { | struct { | ||||
| BMEdge *ele; | BMEdge *ele; | ||||
| int base_index; | int base_index; | ||||
| } e, e_zbuf; | } e, e_zbuf; | ||||
| struct { | struct { | ||||
| BMFace *ele; | BMFace *ele; | ||||
| int base_index; | int base_index; | ||||
| } f, f_zbuf; | } f, f_zbuf; | ||||
| } hit = {{NULL}}; | } hit = {{nullptr}}; | ||||
| /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */ | /* No after-queue (yet), so we check it now, otherwise the em_xxxofs indices are bad. */ | ||||
| if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_FACE)) { | if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_FACE)) { | ||||
| float dist_center = 0.0f; | float dist_center = 0.0f; | ||||
| float *dist_center_p = (em->selectmode & (SCE_SELECT_EDGE | SCE_SELECT_VERTEX)) ? | float *dist_center_p = (em->selectmode & (SCE_SELECT_EDGE | SCE_SELECT_VERTEX)) ? | ||||
| &dist_center : | &dist_center : | ||||
| NULL; | nullptr; | ||||
| uint base_index = 0; | uint base_index = 0; | ||||
| BMFace *efa_zbuf = NULL; | BMFace *efa_zbuf = nullptr; | ||||
| BMFace *efa_test = EDBM_face_find_nearest_ex( | BMFace *efa_test = EDBM_face_find_nearest_ex( | ||||
| vc, &dist, dist_center_p, true, true, use_cycle, &efa_zbuf, bases, bases_len, &base_index); | vc, &dist, dist_center_p, true, true, use_cycle, &efa_zbuf, bases, bases_len, &base_index); | ||||
| if (efa_test && dist_center_p) { | if (efa_test && dist_center_p) { | ||||
| dist = min_ff(dist_margin, dist_center); | dist = min_ff(dist_margin, dist_center); | ||||
| } | } | ||||
| if (efa_test) { | if (efa_test) { | ||||
| hit.f.base_index = base_index; | hit.f.base_index = base_index; | ||||
| hit.f.ele = efa_test; | hit.f.ele = efa_test; | ||||
| } | } | ||||
| if (efa_zbuf) { | if (efa_zbuf) { | ||||
| hit.f_zbuf.base_index = base_index; | hit.f_zbuf.base_index = base_index; | ||||
| hit.f_zbuf.ele = efa_zbuf; | hit.f_zbuf.ele = efa_zbuf; | ||||
| } | } | ||||
| } | } | ||||
| if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_EDGE)) { | if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_EDGE)) { | ||||
| float dist_center = 0.0f; | float dist_center = 0.0f; | ||||
| float *dist_center_p = (em->selectmode & SCE_SELECT_VERTEX) ? &dist_center : NULL; | float *dist_center_p = (em->selectmode & SCE_SELECT_VERTEX) ? &dist_center : nullptr; | ||||
| uint base_index = 0; | uint base_index = 0; | ||||
| BMEdge *eed_zbuf = NULL; | BMEdge *eed_zbuf = nullptr; | ||||
| BMEdge *eed_test = EDBM_edge_find_nearest_ex( | BMEdge *eed_test = EDBM_edge_find_nearest_ex( | ||||
| vc, &dist, dist_center_p, true, use_cycle, &eed_zbuf, bases, bases_len, &base_index); | vc, &dist, dist_center_p, true, use_cycle, &eed_zbuf, bases, bases_len, &base_index); | ||||
| if (eed_test && dist_center_p) { | if (eed_test && dist_center_p) { | ||||
| dist = min_ff(dist_margin, dist_center); | dist = min_ff(dist_margin, dist_center); | ||||
| } | } | ||||
| if (eed_test) { | if (eed_test) { | ||||
| hit.e.base_index = base_index; | hit.e.base_index = base_index; | ||||
| Show All 13 Lines | if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_VERTEX)) { | ||||
| if (eve_test) { | if (eve_test) { | ||||
| hit.v.base_index = base_index; | hit.v.base_index = base_index; | ||||
| hit.v.ele = eve_test; | hit.v.ele = eve_test; | ||||
| } | } | ||||
| } | } | ||||
| /* Return only one of 3 pointers, for front-buffer redraws. */ | /* Return only one of 3 pointers, for front-buffer redraws. */ | ||||
| if (hit.v.ele) { | if (hit.v.ele) { | ||||
| hit.f.ele = NULL; | hit.f.ele = nullptr; | ||||
| hit.e.ele = NULL; | hit.e.ele = nullptr; | ||||
| } | } | ||||
| else if (hit.e.ele) { | else if (hit.e.ele) { | ||||
| hit.f.ele = NULL; | hit.f.ele = nullptr; | ||||
| } | } | ||||
| /* there may be a face under the cursor, who's center if too far away | /* there may be a face under the cursor, who's center if too far away | ||||
| * use this if all else fails, it makes sense to select this */ | * use this if all else fails, it makes sense to select this */ | ||||
| if ((hit.v.ele || hit.e.ele || hit.f.ele) == 0) { | if ((hit.v.ele || hit.e.ele || hit.f.ele) == 0) { | ||||
| if (hit.e_zbuf.ele) { | if (hit.e_zbuf.ele) { | ||||
| hit.e.base_index = hit.e_zbuf.base_index; | hit.e.base_index = hit.e_zbuf.base_index; | ||||
| hit.e.ele = hit.e_zbuf.ele; | hit.e.ele = hit.e_zbuf.ele; | ||||
| } | } | ||||
| else if (hit.f_zbuf.ele) { | else if (hit.f_zbuf.ele) { | ||||
| hit.f.base_index = hit.f_zbuf.base_index; | hit.f.base_index = hit.f_zbuf.base_index; | ||||
| hit.f.ele = hit.f_zbuf.ele; | hit.f.ele = hit.f_zbuf.ele; | ||||
| } | } | ||||
| } | } | ||||
| /* Only one element type will be non-null. */ | /* Only one element type will be non-null. */ | ||||
| BLI_assert(((hit.v.ele != NULL) + (hit.e.ele != NULL) + (hit.f.ele != NULL)) <= 1); | BLI_assert(((hit.v.ele != nullptr) + (hit.e.ele != nullptr) + (hit.f.ele != nullptr)) <= 1); | ||||
| if (hit.v.ele) { | if (hit.v.ele) { | ||||
| *r_base_index = hit.v.base_index; | *r_base_index = hit.v.base_index; | ||||
| } | } | ||||
| if (hit.e.ele) { | if (hit.e.ele) { | ||||
| *r_base_index = hit.e.base_index; | *r_base_index = hit.e.base_index; | ||||
| } | } | ||||
| if (hit.f.ele) { | if (hit.f.ele) { | ||||
| Show All 33 Lines | |||||
| bool EDBM_unified_findnearest_from_raycast(ViewContext *vc, | bool EDBM_unified_findnearest_from_raycast(ViewContext *vc, | ||||
| Base **bases, | Base **bases, | ||||
| const uint bases_len, | const uint bases_len, | ||||
| bool use_boundary_vertices, | bool use_boundary_vertices, | ||||
| bool use_boundary_edges, | bool use_boundary_edges, | ||||
| int *r_base_index_vert, | int *r_base_index_vert, | ||||
| int *r_base_index_edge, | int *r_base_index_edge, | ||||
| int *r_base_index_face, | int *r_base_index_face, | ||||
| struct BMVert **r_eve, | BMVert **r_eve, | ||||
| struct BMEdge **r_eed, | BMEdge **r_eed, | ||||
| struct BMFace **r_efa) | BMFace **r_efa) | ||||
| { | { | ||||
| const float mval_fl[2] = {float(vc->mval[0]), float(vc->mval[1])}; | |||||
| const float mval_fl[2] = {UNPACK2(vc->mval)}; | |||||
| float ray_origin[3], ray_direction[3]; | float ray_origin[3], ray_direction[3]; | ||||
| struct { | struct { | ||||
| uint base_index; | uint base_index; | ||||
| BMElem *ele; | BMElem *ele; | ||||
| } best = {0, NULL}; | } best = {0, nullptr}; | ||||
| /* Currently unused, keep since we may want to pick the best. */ | /* Currently unused, keep since we may want to pick the best. */ | ||||
| UNUSED_VARS(best); | UNUSED_VARS(best); | ||||
| struct { | struct { | ||||
| uint base_index; | uint base_index; | ||||
| BMElem *ele; | BMElem *ele; | ||||
| } best_vert = {0, NULL}; | } best_vert = {0, nullptr}; | ||||
| struct { | struct { | ||||
| uint base_index; | uint base_index; | ||||
| BMElem *ele; | BMElem *ele; | ||||
| } best_edge = {0, NULL}; | } best_edge = {0, nullptr}; | ||||
| struct { | struct { | ||||
| uint base_index; | uint base_index; | ||||
| BMElem *ele; | BMElem *ele; | ||||
| } best_face = {0, NULL}; | } best_face = {0, nullptr}; | ||||
| if (ED_view3d_win_to_ray_clipped( | if (ED_view3d_win_to_ray_clipped( | ||||
| vc->depsgraph, vc->region, vc->v3d, mval_fl, ray_origin, ray_direction, true)) { | vc->depsgraph, vc->region, vc->v3d, mval_fl, ray_origin, ray_direction, true)) { | ||||
| float dist_sq_best = FLT_MAX; | float dist_sq_best = FLT_MAX; | ||||
| float dist_sq_best_vert = FLT_MAX; | float dist_sq_best_vert = FLT_MAX; | ||||
| float dist_sq_best_edge = FLT_MAX; | float dist_sq_best_edge = FLT_MAX; | ||||
| float dist_sq_best_face = FLT_MAX; | float dist_sq_best_face = FLT_MAX; | ||||
| const bool use_vert = (r_eve != NULL); | const bool use_vert = (r_eve != nullptr); | ||||
| const bool use_edge = (r_eed != NULL); | const bool use_edge = (r_eed != nullptr); | ||||
| const bool use_face = (r_efa != NULL); | const bool use_face = (r_efa != nullptr); | ||||
| for (uint base_index = 0; base_index < bases_len; base_index++) { | for (uint base_index = 0; base_index < bases_len; base_index++) { | ||||
| Base *base_iter = bases[base_index]; | Base *base_iter = bases[base_index]; | ||||
| Object *obedit = base_iter->object; | Object *obedit = base_iter->object; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| BMesh *bm = em->bm; | BMesh *bm = em->bm; | ||||
| float imat3[3][3]; | float imat3[3][3]; | ||||
| ED_view3d_viewcontext_init_object(vc, obedit); | ED_view3d_viewcontext_init_object(vc, obedit); | ||||
| copy_m3_m4(imat3, obedit->obmat); | copy_m3_m4(imat3, obedit->obmat); | ||||
| invert_m3(imat3); | invert_m3(imat3); | ||||
| const float(*coords)[3] = NULL; | const float(*coords)[3] = nullptr; | ||||
| { | { | ||||
| Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(vc->depsgraph, obedit->data); | Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(vc->depsgraph, | ||||
| static_cast<ID *>(obedit->data)); | |||||
| if (me_eval->runtime.edit_data) { | if (me_eval->runtime.edit_data) { | ||||
| coords = me_eval->runtime.edit_data->vertexCos; | coords = me_eval->runtime.edit_data->vertexCos; | ||||
| } | } | ||||
| } | } | ||||
| if (coords != NULL) { | if (coords != nullptr) { | ||||
| BM_mesh_elem_index_ensure(bm, BM_VERT); | BM_mesh_elem_index_ensure(bm, BM_VERT); | ||||
| } | } | ||||
| if ((use_boundary_vertices || use_boundary_edges) && (use_vert || use_edge)) { | if ((use_boundary_vertices || use_boundary_edges) && (use_vert || use_edge)) { | ||||
| BMEdge *e; | BMEdge *e; | ||||
| BMIter eiter; | BMIter eiter; | ||||
| BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { | BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { | ||||
| if ((BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false) && (BM_edge_is_boundary(e))) { | if ((BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false) && (BM_edge_is_boundary(e))) { | ||||
| ▲ Show 20 Lines • Show All 133 Lines • ▼ Show 20 Lines | #endif | ||||
| } | } | ||||
| } | } | ||||
| *r_base_index_vert = best_vert.base_index; | *r_base_index_vert = best_vert.base_index; | ||||
| *r_base_index_edge = best_edge.base_index; | *r_base_index_edge = best_edge.base_index; | ||||
| *r_base_index_face = best_face.base_index; | *r_base_index_face = best_face.base_index; | ||||
| if (r_eve) { | if (r_eve) { | ||||
| *r_eve = NULL; | *r_eve = nullptr; | ||||
| } | } | ||||
| if (r_eed) { | if (r_eed) { | ||||
| *r_eed = NULL; | *r_eed = nullptr; | ||||
| } | } | ||||
| if (r_efa) { | if (r_efa) { | ||||
| *r_efa = NULL; | *r_efa = nullptr; | ||||
| } | } | ||||
| if (best_vert.ele) { | if (best_vert.ele) { | ||||
| *r_eve = (BMVert *)best_vert.ele; | *r_eve = (BMVert *)best_vert.ele; | ||||
| } | } | ||||
| if (best_edge.ele) { | if (best_edge.ele) { | ||||
| *r_eed = (BMEdge *)best_edge.ele; | *r_eed = (BMEdge *)best_edge.ele; | ||||
| } | } | ||||
| if (best_face.ele) { | if (best_face.ele) { | ||||
| *r_efa = (BMFace *)best_face.ele; | *r_efa = (BMFace *)best_face.ele; | ||||
| } | } | ||||
| return (best_vert.ele != NULL || best_edge.ele != NULL || best_face.ele != NULL); | return (best_vert.ele != nullptr || best_edge.ele != nullptr || best_face.ele != nullptr); | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Select Similar Region Operator | /** \name Select Similar Region Operator | ||||
| * \{ */ | * \{ */ | ||||
| static int edbm_select_similar_region_exec(bContext *C, wmOperator *op) | static int edbm_select_similar_region_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| Object *obedit = CTX_data_edit_object(C); | Object *obedit = CTX_data_edit_object(C); | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| BMesh *bm = em->bm; | BMesh *bm = em->bm; | ||||
| bool changed = false; | bool changed = false; | ||||
| /* group vars */ | /* group vars */ | ||||
| int *groups_array; | |||||
| int(*group_index)[2]; | int(*group_index)[2]; | ||||
| int group_tot; | int group_tot; | ||||
| int i; | int i; | ||||
| if (bm->totfacesel < 2) { | if (bm->totfacesel < 2) { | ||||
| BKE_report(op->reports, RPT_ERROR, "No face regions selected"); | BKE_report(op->reports, RPT_ERROR, "No face regions selected"); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__); | int *groups_array = static_cast<int *>( | ||||
| MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__)); | |||||
| group_tot = BM_mesh_calc_face_groups( | group_tot = BM_mesh_calc_face_groups( | ||||
| bm, groups_array, &group_index, NULL, NULL, NULL, BM_ELEM_SELECT, BM_VERT); | bm, groups_array, &group_index, nullptr, nullptr, nullptr, BM_ELEM_SELECT, BM_VERT); | ||||
| BM_mesh_elem_table_ensure(bm, BM_FACE); | BM_mesh_elem_table_ensure(bm, BM_FACE); | ||||
| for (i = 0; i < group_tot; i++) { | for (i = 0; i < group_tot; i++) { | ||||
| ListBase faces_regions; | ListBase faces_regions; | ||||
| int tot; | int tot; | ||||
| const int fg_sta = group_index[i][0]; | const int fg_sta = group_index[i][0]; | ||||
| const int fg_len = group_index[i][1]; | const int fg_len = group_index[i][1]; | ||||
| int j; | int j; | ||||
| BMFace **fg = MEM_mallocN(sizeof(*fg) * fg_len, __func__); | BMFace **fg = static_cast<BMFace **>(MEM_mallocN(sizeof(*fg) * fg_len, __func__)); | ||||
| for (j = 0; j < fg_len; j++) { | for (j = 0; j < fg_len; j++) { | ||||
| fg[j] = BM_face_at_index(bm, groups_array[fg_sta + j]); | fg[j] = BM_face_at_index(bm, groups_array[fg_sta + j]); | ||||
| } | } | ||||
| tot = BM_mesh_region_match(bm, fg, fg_len, &faces_regions); | tot = BM_mesh_region_match(bm, fg, fg_len, &faces_regions); | ||||
| MEM_freeN(fg); | MEM_freeN(fg); | ||||
| if (tot) { | if (tot) { | ||||
| LinkData *link; | LinkData *link; | ||||
| while ((link = BLI_pophead(&faces_regions))) { | while ((link = static_cast<LinkData *>(BLI_pophead(&faces_regions)))) { | ||||
| BMFace *f, **faces = link->data; | BMFace *f, **faces = static_cast<BMFace **>(link->data); | ||||
| while ((f = *(faces++))) { | while ((f = *(faces++))) { | ||||
| BM_face_select_set(bm, f, true); | BM_face_select_set(bm, f, true); | ||||
| } | } | ||||
| MEM_freeN(link->data); | MEM_freeN(link->data); | ||||
| MEM_freeN(link); | MEM_freeN(link); | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| MEM_freeN(groups_array); | MEM_freeN(groups_array); | ||||
| MEM_freeN(group_index); | MEM_freeN(group_index); | ||||
| if (changed) { | if (changed) { | ||||
| DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); | DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | ||||
| } | } | ||||
| else { | else { | ||||
| BKE_report(op->reports, RPT_WARNING, "No matching face regions found"); | BKE_report(op->reports, RPT_WARNING, "No matching face regions found"); | ||||
| } | } | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | static int edbm_select_mode_invoke(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| } | } | ||||
| if (!RNA_struct_property_is_set(op->ptr, "use_expand")) { | if (!RNA_struct_property_is_set(op->ptr, "use_expand")) { | ||||
| RNA_boolean_set(op->ptr, "use_expand", event->modifier & KM_CTRL); | RNA_boolean_set(op->ptr, "use_expand", event->modifier & KM_CTRL); | ||||
| } | } | ||||
| return edbm_select_mode_exec(C, op); | return edbm_select_mode_exec(C, op); | ||||
| } | } | ||||
| static char *edbm_select_mode_get_description(struct bContext *UNUSED(C), | static char *edbm_select_mode_get_description(bContext *UNUSED(C), | ||||
| struct wmOperatorType *UNUSED(op), | wmOperatorType *UNUSED(op), | ||||
| struct PointerRNA *values) | PointerRNA *values) | ||||
| { | { | ||||
| const int type = RNA_enum_get(values, "type"); | const int type = RNA_enum_get(values, "type"); | ||||
| /* Because the special behavior for shift and ctrl click depend on user input, they may be | /* Because the special behavior for shift and ctrl click depend on user input, they may be | ||||
| * incorrect if the operator is used from a script or from a special button. So only return the | * incorrect if the operator is used from a script or from a special button. So only return the | ||||
| * specialized descriptions if only the "type" is set, which conveys that the operator is meant | * specialized descriptions if only the "type" is set, which conveys that the operator is meant | ||||
| * to be used with the logic in the `invoke` method. */ | * to be used with the logic in the `invoke` method. */ | ||||
| if (RNA_struct_property_is_set(values, "type") && | if (RNA_struct_property_is_set(values, "type") && | ||||
| Show All 9 Lines | switch (type) { | ||||
| TIP_("Edge select - Shift-Click for multiple modes, " | TIP_("Edge select - Shift-Click for multiple modes, " | ||||
| "Ctrl-Click expands/contracts selection depending on the current mode")); | "Ctrl-Click expands/contracts selection depending on the current mode")); | ||||
| case SCE_SELECT_FACE: | case SCE_SELECT_FACE: | ||||
| return BLI_strdup( | return BLI_strdup( | ||||
| TIP_("Face select - Shift-Click for multiple modes, Ctrl-Click expands selection")); | TIP_("Face select - Shift-Click for multiple modes, Ctrl-Click expands selection")); | ||||
| } | } | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| void MESH_OT_select_mode(wmOperatorType *ot) | void MESH_OT_select_mode(wmOperatorType *ot) | ||||
| { | { | ||||
| PropertyRNA *prop; | PropertyRNA *prop; | ||||
| static const EnumPropertyItem actions_items[] = { | static const EnumPropertyItem actions_items[] = { | ||||
| {0, "DISABLE", 0, "Disable", "Disable selected markers"}, | {0, "DISABLE", 0, "Disable", "Disable selected markers"}, | ||||
| {1, "ENABLE", 0, "Enable", "Enable selected markers"}, | {1, "ENABLE", 0, "Enable", "Enable selected markers"}, | ||||
| {2, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"}, | {2, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"}, | ||||
| {0, NULL, 0, NULL, NULL}, | {0, nullptr, 0, nullptr, nullptr}, | ||||
| }; | }; | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Select Mode"; | ot->name = "Select Mode"; | ||||
| ot->idname = "MESH_OT_select_mode"; | ot->idname = "MESH_OT_select_mode"; | ||||
| ot->description = "Change selection mode"; | ot->description = "Change selection mode"; | ||||
| /* api callbacks */ | /* api callbacks */ | ||||
| ot->invoke = edbm_select_mode_invoke; | ot->invoke = edbm_select_mode_invoke; | ||||
| ot->exec = edbm_select_mode_exec; | ot->exec = edbm_select_mode_exec; | ||||
| ot->poll = ED_operator_editmesh; | ot->poll = ED_operator_editmesh; | ||||
| ot->get_description = edbm_select_mode_get_description; | ot->get_description = edbm_select_mode_get_description; | ||||
| /* flags */ | /* flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* properties */ | /* properties */ | ||||
| /* Hide all, not to show redo panel. */ | /* Hide all, not to show redo panel. */ | ||||
| prop = RNA_def_boolean(ot->srna, "use_extend", false, "Extend", ""); | prop = RNA_def_boolean(ot->srna, "use_extend", false, "Extend", ""); | ||||
| RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); | RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN | PROP_SKIP_SAVE)); | ||||
| prop = RNA_def_boolean(ot->srna, "use_expand", false, "Expand", ""); | prop = RNA_def_boolean(ot->srna, "use_expand", false, "Expand", ""); | ||||
| RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); | RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN | PROP_SKIP_SAVE)); | ||||
| ot->prop = prop = RNA_def_enum(ot->srna, "type", rna_enum_mesh_select_mode_items, 0, "Type", ""); | ot->prop = prop = RNA_def_enum(ot->srna, "type", rna_enum_mesh_select_mode_items, 0, "Type", ""); | ||||
| RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); | RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN | PROP_SKIP_SAVE)); | ||||
| prop = RNA_def_enum( | prop = RNA_def_enum( | ||||
| ot->srna, "action", actions_items, 2, "Action", "Selection action to execute"); | ot->srna, "action", actions_items, 2, "Action", "Selection action to execute"); | ||||
| RNA_def_property_flag(prop, PROP_HIDDEN); | RNA_def_property_flag(prop, PROP_HIDDEN); | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| Show All 16 Lines | BMW_init(&walker, | ||||
| bm, | bm, | ||||
| walkercode, | walkercode, | ||||
| BMW_MASK_NOP, | BMW_MASK_NOP, | ||||
| BMW_MASK_NOP, | BMW_MASK_NOP, | ||||
| BMW_MASK_NOP, | BMW_MASK_NOP, | ||||
| BMW_FLAG_TEST_HIDDEN, | BMW_FLAG_TEST_HIDDEN, | ||||
| BMW_NIL_LAY); | BMW_NIL_LAY); | ||||
| for (ele = BMW_begin(&walker, start); ele; ele = BMW_step(&walker)) { | for (ele = static_cast<BMElem *>(BMW_begin(&walker, start)); ele; | ||||
| ele = static_cast<BMElem *>(BMW_step(&walker))) { | |||||
| r_count_by_select[BM_elem_flag_test(ele, BM_ELEM_SELECT) ? 1 : 0] += 1; | r_count_by_select[BM_elem_flag_test(ele, BM_ELEM_SELECT) ? 1 : 0] += 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; | ||||
| } | } | ||||
| } | } | ||||
| Show All 11 Lines | BMW_init(&walker, | ||||
| bm, | bm, | ||||
| walkercode, | walkercode, | ||||
| BMW_MASK_NOP, | BMW_MASK_NOP, | ||||
| BMW_MASK_NOP, | BMW_MASK_NOP, | ||||
| BMW_MASK_NOP, | BMW_MASK_NOP, | ||||
| BMW_FLAG_TEST_HIDDEN, | BMW_FLAG_TEST_HIDDEN, | ||||
| BMW_NIL_LAY); | BMW_NIL_LAY); | ||||
| for (ele = BMW_begin(&walker, start); ele; ele = BMW_step(&walker)) { | for (ele = static_cast<BMElem *>(BMW_begin(&walker, start)); ele; | ||||
| ele = static_cast<BMElem *>(BMW_step(&walker))) { | |||||
| if (!select) { | if (!select) { | ||||
| BM_select_history_remove(bm, ele); | BM_select_history_remove(bm, ele); | ||||
| } | } | ||||
| BM_elem_select_set(bm, ele, select); | BM_elem_select_set(bm, ele, select); | ||||
| } | } | ||||
| BMW_end(&walker); | BMW_end(&walker); | ||||
| } | } | ||||
| Show All 9 Lines | 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); | ||||
| if (em->bm->totedgesel == 0) { | if (em->bm->totedgesel == 0) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BMEdge *eed; | BMEdge *eed; | ||||
| BMEdge **edarray; | |||||
| int edindex; | int edindex; | ||||
| BMIter iter; | BMIter iter; | ||||
| int totedgesel = 0; | int totedgesel = 0; | ||||
| BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { | BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { | ||||
| if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { | if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { | ||||
| totedgesel++; | totedgesel++; | ||||
| } | } | ||||
| } | } | ||||
| edarray = MEM_mallocN(sizeof(BMEdge *) * totedgesel, "edge array"); | BMEdge **edarray = static_cast<BMEdge **>( | ||||
| MEM_mallocN(sizeof(BMEdge *) * totedgesel, "edge array")); | |||||
| edindex = 0; | edindex = 0; | ||||
| BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { | BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { | ||||
| if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { | if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { | ||||
| edarray[edindex] = eed; | edarray[edindex] = eed; | ||||
| edindex++; | edindex++; | ||||
| } | } | ||||
| } | } | ||||
| Show All 16 Lines | else { | ||||
| walker_select(em, BMW_EDGELOOP, eed, true); | walker_select(em, BMW_EDGELOOP, eed, true); | ||||
| } | } | ||||
| } | } | ||||
| EDBM_selectmode_flush(em); | EDBM_selectmode_flush(em); | ||||
| } | } | ||||
| MEM_freeN(edarray); | MEM_freeN(edarray); | ||||
| // if (EM_texFaceCheck()) | // if (EM_texFaceCheck()) | ||||
| DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); | DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | ||||
| } | } | ||||
| MEM_freeN(objects); | MEM_freeN(objects); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void MESH_OT_loop_multi_select(wmOperatorType *ot) | void MESH_OT_loop_multi_select(wmOperatorType *ot) | ||||
| ▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | static void mouse_mesh_loop_edge( | ||||
| else { | else { | ||||
| walker_select(em, BMW_EDGELOOP, eed, select); | walker_select(em, BMW_EDGELOOP, eed, select); | ||||
| } | } | ||||
| } | } | ||||
| static bool mouse_mesh_loop( | static bool mouse_mesh_loop( | ||||
| bContext *C, const int mval[2], bool extend, bool deselect, bool toggle, bool ring) | bContext *C, const int mval[2], bool extend, bool deselect, bool toggle, bool ring) | ||||
| { | { | ||||
| Base *basact = NULL; | Base *basact = nullptr; | ||||
| BMVert *eve = NULL; | BMVert *eve = nullptr; | ||||
| BMEdge *eed = NULL; | BMEdge *eed = nullptr; | ||||
| BMFace *efa = NULL; | BMFace *efa = nullptr; | ||||
| ViewContext vc; | ViewContext vc; | ||||
| BMEditMesh *em; | BMEditMesh *em; | ||||
| bool select = true; | bool select = true; | ||||
| bool select_clear = false; | bool select_clear = false; | ||||
| bool select_cycle = true; | bool select_cycle = true; | ||||
| float mvalf[2]; | float mvalf[2]; | ||||
| em_setup_viewcontext(C, &vc); | em_setup_viewcontext(C, &vc); | ||||
| mvalf[0] = (float)(vc.mval[0] = mval[0]); | mvalf[0] = float(vc.mval[0] = mval[0]); | ||||
| mvalf[1] = (float)(vc.mval[1] = mval[1]); | mvalf[1] = float(vc.mval[1] = mval[1]); | ||||
| BMEditMesh *em_original = vc.em; | BMEditMesh *em_original = vc.em; | ||||
| const short selectmode = em_original->selectmode; | const short selectmode = em_original->selectmode; | ||||
| em_original->selectmode = SCE_SELECT_EDGE; | em_original->selectmode = SCE_SELECT_EDGE; | ||||
| uint bases_len; | uint bases_len; | ||||
| Base **bases = BKE_view_layer_array_from_bases_in_edit_mode( | Base **bases = BKE_view_layer_array_from_bases_in_edit_mode( | ||||
| vc.scene, vc.view_layer, vc.v3d, &bases_len); | vc.scene, vc.view_layer, vc.v3d, &bases_len); | ||||
| { | { | ||||
| int base_index = -1; | int base_index = -1; | ||||
| if (EDBM_unified_findnearest(&vc, bases, bases_len, &base_index, &eve, &eed, &efa)) { | if (EDBM_unified_findnearest(&vc, bases, bases_len, &base_index, &eve, &eed, &efa)) { | ||||
| basact = bases[base_index]; | basact = bases[base_index]; | ||||
| ED_view3d_viewcontext_init_object(&vc, basact->object); | ED_view3d_viewcontext_init_object(&vc, basact->object); | ||||
| em = vc.em; | em = vc.em; | ||||
| } | } | ||||
| else { | else { | ||||
| em = NULL; | em = nullptr; | ||||
| } | } | ||||
| } | } | ||||
| em_original->selectmode = selectmode; | em_original->selectmode = selectmode; | ||||
| if (em == NULL || eed == NULL) { | if (em == nullptr || eed == nullptr) { | ||||
| MEM_freeN(bases); | MEM_freeN(bases); | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (extend == false && deselect == false && toggle == false) { | if (extend == false && deselect == false && toggle == false) { | ||||
| select_clear = true; | select_clear = true; | ||||
| } | } | ||||
| Show All 21 Lines | for (uint base_index = 0; base_index < bases_len; base_index++) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (em_iter == em) { | if (em_iter == em) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| EDBM_flag_disable_all(em_iter, BM_ELEM_SELECT); | EDBM_flag_disable_all(em_iter, BM_ELEM_SELECT); | ||||
| DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT); | DEG_id_tag_update(static_cast<ID *>(ob_iter->data), ID_RECALC_SELECT); | ||||
| } | } | ||||
| } | } | ||||
| if (em->selectmode & SCE_SELECT_FACE) { | if (em->selectmode & SCE_SELECT_FACE) { | ||||
| mouse_mesh_loop_face(em, eed, select, select_clear); | mouse_mesh_loop_face(em, eed, select, select_clear); | ||||
| } | } | ||||
| else { | else { | ||||
| if (ring) { | if (ring) { | ||||
| Show All 37 Lines | #endif | ||||
| else if (em->selectmode & SCE_SELECT_EDGE) { | else if (em->selectmode & SCE_SELECT_EDGE) { | ||||
| BM_select_history_store(em->bm, eed); | BM_select_history_store(em->bm, eed); | ||||
| } | } | ||||
| else if (em->selectmode & SCE_SELECT_FACE) { | else if (em->selectmode & SCE_SELECT_FACE) { | ||||
| /* Select the face of eed which is the nearest of mouse. */ | /* Select the face of eed which is the nearest of mouse. */ | ||||
| BMFace *f; | BMFace *f; | ||||
| BMIter iterf; | BMIter iterf; | ||||
| float best_dist = FLT_MAX; | float best_dist = FLT_MAX; | ||||
| efa = NULL; | efa = nullptr; | ||||
| /* We can't be sure this has already been set... */ | /* We can't be sure this has already been set... */ | ||||
| ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); | ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); | ||||
| BM_ITER_ELEM (f, &iterf, eed, BM_FACES_OF_EDGE) { | BM_ITER_ELEM (f, &iterf, eed, BM_FACES_OF_EDGE) { | ||||
| if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { | if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { | ||||
| float cent[3]; | float cent[3]; | ||||
| float co[2], tdist; | float co[2], tdist; | ||||
| Show All 14 Lines | else if (em->selectmode & SCE_SELECT_FACE) { | ||||
| BM_mesh_active_face_set(em->bm, efa); | BM_mesh_active_face_set(em->bm, efa); | ||||
| BM_select_history_store(em->bm, efa); | BM_select_history_store(em->bm, efa); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| MEM_freeN(bases); | MEM_freeN(bases); | ||||
| DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT); | DEG_id_tag_update(static_cast<ID *>(vc.obedit->data), ID_RECALC_SELECT); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); | ||||
| return true; | return true; | ||||
| } | } | ||||
| static int edbm_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event) | static int edbm_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 101 Lines • ▼ Show 20 Lines | switch (action) { | ||||
| case SEL_DESELECT: | case SEL_DESELECT: | ||||
| EDBM_flag_disable_all(em, BM_ELEM_SELECT); | EDBM_flag_disable_all(em, BM_ELEM_SELECT); | ||||
| break; | break; | ||||
| case SEL_INVERT: | case SEL_INVERT: | ||||
| EDBM_select_swap(em); | EDBM_select_swap(em); | ||||
| EDBM_selectmode_flush(em); | EDBM_selectmode_flush(em); | ||||
| break; | break; | ||||
| } | } | ||||
| DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); | DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | ||||
| } | } | ||||
| MEM_freeN(objects); | MEM_freeN(objects); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| Show All 31 Lines | static int edbm_faces_select_interior_exec(bContext *C, wmOperator *UNUSED(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); | ||||
| if (!EDBM_select_interior_faces(em)) { | if (!EDBM_select_interior_faces(em)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); | DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | ||||
| } | } | ||||
| MEM_freeN(objects); | MEM_freeN(objects); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void MESH_OT_select_interior_faces(wmOperatorType *ot) | void MESH_OT_select_interior_faces(wmOperatorType *ot) | ||||
| Show All 15 Lines | |||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Select Picking API | /** \name Select Picking API | ||||
| * | * | ||||
| * Here actual select happens, | * Here actual select happens, | ||||
| * Gets called via generic mouse select operator. | * Gets called via generic mouse select operator. | ||||
| * \{ */ | * \{ */ | ||||
| bool EDBM_select_pick(bContext *C, const int mval[2], const struct SelectPick_Params *params) | bool EDBM_select_pick(bContext *C, const int mval[2], const SelectPick_Params *params) | ||||
| { | { | ||||
| ViewContext vc; | ViewContext vc; | ||||
| int base_index_active = -1; | int base_index_active = -1; | ||||
| BMVert *eve = NULL; | BMVert *eve = nullptr; | ||||
| BMEdge *eed = NULL; | BMEdge *eed = nullptr; | ||||
| BMFace *efa = NULL; | BMFace *efa = nullptr; | ||||
| /* setup view context for argument to callbacks */ | /* setup view context for argument to callbacks */ | ||||
| em_setup_viewcontext(C, &vc); | em_setup_viewcontext(C, &vc); | ||||
| vc.mval[0] = mval[0]; | vc.mval[0] = mval[0]; | ||||
| vc.mval[1] = mval[1]; | vc.mval[1] = mval[1]; | ||||
| uint bases_len = 0; | uint bases_len = 0; | ||||
| Base **bases = BKE_view_layer_array_from_bases_in_edit_mode( | Base **bases = BKE_view_layer_array_from_bases_in_edit_mode( | ||||
| vc.scene, vc.view_layer, vc.v3d, &bases_len); | vc.scene, vc.view_layer, vc.v3d, &bases_len); | ||||
| bool changed = false; | bool changed = false; | ||||
| bool found = unified_findnearest(&vc, bases, bases_len, &base_index_active, &eve, &eed, &efa); | bool found = unified_findnearest(&vc, bases, bases_len, &base_index_active, &eve, &eed, &efa); | ||||
| if (params->sel_op == SEL_OP_SET) { | if (params->sel_op == SEL_OP_SET) { | ||||
| BMElem *ele = efa ? (BMElem *)efa : (eed ? (BMElem *)eed : (BMElem *)eve); | BMElem *ele = efa ? (BMElem *)efa : (eed ? (BMElem *)eed : (BMElem *)eve); | ||||
| if ((found && params->select_passthrough) && BM_elem_flag_test(ele, BM_ELEM_SELECT)) { | if ((found && params->select_passthrough) && BM_elem_flag_test(ele, BM_ELEM_SELECT)) { | ||||
| found = false; | found = false; | ||||
| } | } | ||||
| else if (found || params->deselect_all) { | else if (found || params->deselect_all) { | ||||
| /* Deselect everything. */ | /* Deselect everything. */ | ||||
| for (uint base_index = 0; base_index < bases_len; base_index++) { | for (uint base_index = 0; base_index < bases_len; base_index++) { | ||||
| Base *base_iter = bases[base_index]; | Base *base_iter = bases[base_index]; | ||||
| Object *ob_iter = base_iter->object; | Object *ob_iter = base_iter->object; | ||||
| EDBM_flag_disable_all(BKE_editmesh_from_object(ob_iter), BM_ELEM_SELECT); | EDBM_flag_disable_all(BKE_editmesh_from_object(ob_iter), BM_ELEM_SELECT); | ||||
| DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT); | DEG_id_tag_update(static_cast<ID *>(ob_iter->data), ID_RECALC_SELECT); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data); | ||||
| } | } | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| if (found) { | if (found) { | ||||
| Base *basact = bases[base_index_active]; | Base *basact = bases[base_index_active]; | ||||
| ▲ Show 20 Lines • Show All 127 Lines • ▼ Show 20 Lines | if (found) { | ||||
| EDBM_selectmode_flush(vc.em); | EDBM_selectmode_flush(vc.em); | ||||
| if (efa) { | if (efa) { | ||||
| /* Change active material on object. */ | /* Change active material on object. */ | ||||
| if (efa->mat_nr != vc.obedit->actcol - 1) { | if (efa->mat_nr != vc.obedit->actcol - 1) { | ||||
| vc.obedit->actcol = efa->mat_nr + 1; | vc.obedit->actcol = efa->mat_nr + 1; | ||||
| vc.em->mat_nr = efa->mat_nr; | vc.em->mat_nr = efa->mat_nr; | ||||
| WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, NULL); | WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, nullptr); | ||||
| } | } | ||||
| /* Change active face-map on object. */ | /* Change active face-map on object. */ | ||||
| if (!BLI_listbase_is_empty(&vc.obedit->fmaps)) { | if (!BLI_listbase_is_empty(&vc.obedit->fmaps)) { | ||||
| const int cd_fmap_offset = CustomData_get_offset(&vc.em->bm->pdata, CD_FACEMAP); | const int cd_fmap_offset = CustomData_get_offset(&vc.em->bm->pdata, CD_FACEMAP); | ||||
| if (cd_fmap_offset != -1) { | if (cd_fmap_offset != -1) { | ||||
| int map = *((int *)BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset)); | int map = *((int *)BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset)); | ||||
| if ((map < -1) || (map > BLI_listbase_count_at_most(&vc.obedit->fmaps, map))) { | if ((map < -1) || (map > BLI_listbase_count_at_most(&vc.obedit->fmaps, map))) { | ||||
| Show All 11 Lines | if (found) { | ||||
| /* Changing active object is handy since it allows us to | /* Changing active object is handy since it allows us to | ||||
| * switch UV layers, vgroups for eg. */ | * switch UV layers, vgroups for eg. */ | ||||
| BKE_view_layer_synced_ensure(vc.scene, vc.view_layer); | BKE_view_layer_synced_ensure(vc.scene, vc.view_layer); | ||||
| if (BKE_view_layer_active_base_get(vc.view_layer) != basact) { | if (BKE_view_layer_active_base_get(vc.view_layer) != basact) { | ||||
| ED_object_base_activate(C, basact); | ED_object_base_activate(C, basact); | ||||
| } | } | ||||
| DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT); | DEG_id_tag_update(static_cast<ID *>(vc.obedit->data), ID_RECALC_SELECT); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| MEM_freeN(bases); | MEM_freeN(bases); | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Select Mode Utilities | /** \name Select Mode Utilities | ||||
| * \{ */ | * \{ */ | ||||
| static void edbm_strip_selections(BMEditMesh *em) | static void edbm_strip_selections(BMEditMesh *em) | ||||
| { | { | ||||
| BMEditSelection *ese, *nextese; | BMEditSelection *ese, *nextese; | ||||
| if (!(em->selectmode & SCE_SELECT_VERTEX)) { | if (!(em->selectmode & SCE_SELECT_VERTEX)) { | ||||
| ese = em->bm->selected.first; | ese = static_cast<BMEditSelection *>(em->bm->selected.first); | ||||
| while (ese) { | while (ese) { | ||||
| nextese = ese->next; | nextese = ese->next; | ||||
| if (ese->htype == BM_VERT) { | if (ese->htype == BM_VERT) { | ||||
| BLI_freelinkN(&(em->bm->selected), ese); | BLI_freelinkN(&(em->bm->selected), ese); | ||||
| } | } | ||||
| ese = nextese; | ese = nextese; | ||||
| } | } | ||||
| } | } | ||||
| if (!(em->selectmode & SCE_SELECT_EDGE)) { | if (!(em->selectmode & SCE_SELECT_EDGE)) { | ||||
| ese = em->bm->selected.first; | ese = static_cast<BMEditSelection *>(em->bm->selected.first); | ||||
| while (ese) { | while (ese) { | ||||
| nextese = ese->next; | nextese = ese->next; | ||||
| if (ese->htype == BM_EDGE) { | if (ese->htype == BM_EDGE) { | ||||
| BLI_freelinkN(&(em->bm->selected), ese); | BLI_freelinkN(&(em->bm->selected), ese); | ||||
| } | } | ||||
| ese = nextese; | ese = nextese; | ||||
| } | } | ||||
| } | } | ||||
| if (!(em->selectmode & SCE_SELECT_FACE)) { | if (!(em->selectmode & SCE_SELECT_FACE)) { | ||||
| ese = em->bm->selected.first; | ese = static_cast<BMEditSelection *>(em->bm->selected.first); | ||||
| while (ese) { | while (ese) { | ||||
| nextese = ese->next; | nextese = ese->next; | ||||
| if (ese->htype == BM_FACE) { | if (ese->htype == BM_FACE) { | ||||
| BLI_freelinkN(&(em->bm->selected), ese); | BLI_freelinkN(&(em->bm->selected), ese); | ||||
| } | } | ||||
| ese = nextese; | ese = nextese; | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 164 Lines • ▼ Show 20 Lines | bool EDBM_selectmode_toggle_multi(bContext *C, | ||||
| const int action, | const int action, | ||||
| const bool use_extend, | const bool use_extend, | ||||
| const bool use_expand) | const bool use_expand) | ||||
| { | { | ||||
| 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); | ||||
| ToolSettings *ts = CTX_data_tool_settings(C); | ToolSettings *ts = CTX_data_tool_settings(C); | ||||
| Object *obedit = CTX_data_edit_object(C); | Object *obedit = CTX_data_edit_object(C); | ||||
| BMEditMesh *em = NULL; | BMEditMesh *em = nullptr; | ||||
| bool ret = false; | bool ret = false; | ||||
| if (obedit && obedit->type == OB_MESH) { | if (obedit && obedit->type == OB_MESH) { | ||||
| em = BKE_editmesh_from_object(obedit); | em = BKE_editmesh_from_object(obedit); | ||||
| } | } | ||||
| if (em == NULL) { | if (em == nullptr) { | ||||
| return ret; | return ret; | ||||
| } | } | ||||
| bool only_update = false; | bool only_update = false; | ||||
| switch (action) { | switch (action) { | ||||
| case -1: | case -1: | ||||
| /* already set */ | /* already set */ | ||||
| break; | break; | ||||
| ▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | case SCE_SELECT_FACE: | ||||
| break; | break; | ||||
| default: | default: | ||||
| BLI_assert(0); | BLI_assert(0); | ||||
| break; | break; | ||||
| } | } | ||||
| if (ret == true) { | if (ret == true) { | ||||
| ts->selectmode = em->selectmode; | ts->selectmode = em->selectmode; | ||||
| em = NULL; | em = nullptr; | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| Object *ob_iter = objects[ob_index]; | Object *ob_iter = objects[ob_index]; | ||||
| BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter); | BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter); | ||||
| em_iter->selectmode = ts->selectmode; | em_iter->selectmode = ts->selectmode; | ||||
| EDBM_selectmode_set(em_iter); | EDBM_selectmode_set(em_iter); | ||||
| DEG_id_tag_update(ob_iter->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); | DEG_id_tag_update(static_cast<ID *>(ob_iter->data), | ||||
| ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); | |||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data); | ||||
| } | } | ||||
| WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL); | WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, nullptr); | ||||
| DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); | DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); | ||||
| } | } | ||||
| MEM_freeN(objects); | MEM_freeN(objects); | ||||
| return ret; | return ret; | ||||
| } | } | ||||
| bool EDBM_selectmode_set_multi(bContext *C, const short selectmode) | bool EDBM_selectmode_set_multi(bContext *C, const short selectmode) | ||||
| { | { | ||||
| BLI_assert(selectmode != 0); | BLI_assert(selectmode != 0); | ||||
| bool changed = false; | bool changed = false; | ||||
| { | { | ||||
| Object *obedit = CTX_data_edit_object(C); | Object *obedit = CTX_data_edit_object(C); | ||||
| BMEditMesh *em = NULL; | BMEditMesh *em = nullptr; | ||||
| if (obedit && obedit->type == OB_MESH) { | if (obedit && obedit->type == OB_MESH) { | ||||
| em = BKE_editmesh_from_object(obedit); | em = BKE_editmesh_from_object(obedit); | ||||
| } | } | ||||
| if (em == NULL) { | if (em == nullptr) { | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| } | } | ||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| Scene *scene = CTX_data_scene(C); | Scene *scene = CTX_data_scene(C); | ||||
| ToolSettings *ts = scene->toolsettings; | ToolSettings *ts = scene->toolsettings; | ||||
| if (ts->selectmode != selectmode) { | if (ts->selectmode != selectmode) { | ||||
| ts->selectmode = selectmode; | ts->selectmode = selectmode; | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| uint objects_len = 0; | uint objects_len = 0; | ||||
| Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( | Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( | ||||
| scene, view_layer, CTX_wm_view3d(C), &objects_len); | scene, view_layer, CTX_wm_view3d(C), &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 *ob_iter = objects[ob_index]; | Object *ob_iter = objects[ob_index]; | ||||
| BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter); | BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter); | ||||
| if (em_iter->selectmode != ts->selectmode) { | if (em_iter->selectmode != ts->selectmode) { | ||||
| em_iter->selectmode = ts->selectmode; | em_iter->selectmode = ts->selectmode; | ||||
| EDBM_selectmode_set(em_iter); | EDBM_selectmode_set(em_iter); | ||||
| DEG_id_tag_update(ob_iter->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); | DEG_id_tag_update(static_cast<ID *>(ob_iter->data), | ||||
| ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); | |||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data); | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| MEM_freeN(objects); | MEM_freeN(objects); | ||||
| if (changed) { | if (changed) { | ||||
| WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL); | WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, nullptr); | ||||
| DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); | DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); | ||||
| } | } | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| bool EDBM_selectmode_disable(Scene *scene, | bool EDBM_selectmode_disable(Scene *scene, | ||||
| BMEditMesh *em, | BMEditMesh *em, | ||||
| const short selectmode_disable, | const short selectmode_disable, | ||||
| ▲ Show 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { | if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_face_select_set(em->bm, efa, !BM_elem_flag_test(efa, BM_ELEM_SELECT)); | BM_face_select_set(em->bm, efa, !BM_elem_flag_test(efa, BM_ELEM_SELECT)); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| bool EDBM_mesh_deselect_all_multi_ex(struct Base **bases, const uint bases_len) | bool EDBM_mesh_deselect_all_multi_ex(Base **bases, const uint bases_len) | ||||
| { | { | ||||
| bool changed_multi = false; | bool changed_multi = false; | ||||
| for (uint base_index = 0; base_index < bases_len; base_index++) { | for (uint base_index = 0; base_index < bases_len; base_index++) { | ||||
| Base *base_iter = bases[base_index]; | Base *base_iter = bases[base_index]; | ||||
| Object *ob_iter = base_iter->object; | Object *ob_iter = base_iter->object; | ||||
| BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter); | BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter); | ||||
| if (em_iter->bm->totvertsel == 0) { | if (em_iter->bm->totvertsel == 0) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| EDBM_flag_disable_all(em_iter, BM_ELEM_SELECT); | EDBM_flag_disable_all(em_iter, BM_ELEM_SELECT); | ||||
| DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT); | DEG_id_tag_update(static_cast<ID *>(ob_iter->data), ID_RECALC_SELECT); | ||||
| changed_multi = true; | changed_multi = true; | ||||
| } | } | ||||
| return changed_multi; | return changed_multi; | ||||
| } | } | ||||
| bool EDBM_mesh_deselect_all_multi(struct bContext *C) | bool EDBM_mesh_deselect_all_multi(bContext *C) | ||||
| { | { | ||||
| Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); | Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); | ||||
| ViewContext vc; | ViewContext vc; | ||||
| ED_view3d_viewcontext_init(C, &vc, depsgraph); | ED_view3d_viewcontext_init(C, &vc, depsgraph); | ||||
| uint bases_len = 0; | uint bases_len = 0; | ||||
| Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data( | Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data( | ||||
| vc.scene, vc.view_layer, vc.v3d, &bases_len); | vc.scene, vc.view_layer, vc.v3d, &bases_len); | ||||
| bool changed_multi = EDBM_mesh_deselect_all_multi_ex(bases, bases_len); | bool changed_multi = EDBM_mesh_deselect_all_multi_ex(bases, bases_len); | ||||
| MEM_freeN(bases); | MEM_freeN(bases); | ||||
| return changed_multi; | return changed_multi; | ||||
| } | } | ||||
| bool EDBM_selectmode_disable_multi_ex(Scene *scene, | bool EDBM_selectmode_disable_multi_ex(Scene *scene, | ||||
| struct Base **bases, | Base **bases, | ||||
| const uint bases_len, | const uint bases_len, | ||||
| const short selectmode_disable, | const short selectmode_disable, | ||||
| const short selectmode_fallback) | const short selectmode_fallback) | ||||
| { | { | ||||
| bool changed_multi = false; | bool changed_multi = false; | ||||
| for (uint base_index = 0; base_index < bases_len; base_index++) { | for (uint base_index = 0; base_index < bases_len; base_index++) { | ||||
| Base *base_iter = bases[base_index]; | Base *base_iter = bases[base_index]; | ||||
| Object *ob_iter = base_iter->object; | Object *ob_iter = base_iter->object; | ||||
| BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter); | BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter); | ||||
| if (EDBM_selectmode_disable(scene, em_iter, selectmode_disable, selectmode_fallback)) { | if (EDBM_selectmode_disable(scene, em_iter, selectmode_disable, selectmode_fallback)) { | ||||
| changed_multi = true; | changed_multi = true; | ||||
| } | } | ||||
| } | } | ||||
| return changed_multi; | return changed_multi; | ||||
| } | } | ||||
| bool EDBM_selectmode_disable_multi(struct bContext *C, | bool EDBM_selectmode_disable_multi(bContext *C, | ||||
| const short selectmode_disable, | const short selectmode_disable, | ||||
| const short selectmode_fallback) | const short selectmode_fallback) | ||||
| { | { | ||||
| 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); | ||||
| ViewContext vc; | ViewContext vc; | ||||
| ED_view3d_viewcontext_init(C, &vc, depsgraph); | ED_view3d_viewcontext_init(C, &vc, depsgraph); | ||||
| uint bases_len = 0; | uint bases_len = 0; | ||||
| Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data( | Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data( | ||||
| vc.scene, vc.view_layer, NULL, &bases_len); | vc.scene, vc.view_layer, nullptr, &bases_len); | ||||
| bool changed_multi = EDBM_selectmode_disable_multi_ex( | bool changed_multi = EDBM_selectmode_disable_multi_ex( | ||||
| scene, bases, bases_len, selectmode_disable, selectmode_fallback); | scene, bases, bases_len, selectmode_disable, selectmode_fallback); | ||||
| MEM_freeN(bases); | MEM_freeN(bases); | ||||
| return changed_multi; | return changed_multi; | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| ▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | |||||
| */ | */ | ||||
| static float bm_interior_face_group_calc_cost(ListBase *ls, const float *edge_lengths) | static float bm_interior_face_group_calc_cost(ListBase *ls, const float *edge_lengths) | ||||
| { | { | ||||
| /* Dividing by the area is important so larger face groups (which will become the outer shell) | /* Dividing by the area is important so larger face groups (which will become the outer shell) | ||||
| * aren't detected as having a high cost. */ | * aren't detected as having a high cost. */ | ||||
| float area = 0.0f; | float area = 0.0f; | ||||
| float cost = 0.0f; | float cost = 0.0f; | ||||
| bool found = false; | bool found = false; | ||||
| LISTBASE_FOREACH (struct BMFaceLink *, f_link, ls) { | LISTBASE_FOREACH (BMFaceLink *, f_link, ls) { | ||||
| BMFace *f = f_link->face; | BMFace *f = f_link->face; | ||||
| area += f_link->area; | area += f_link->area; | ||||
| int i = BM_elem_index_get(f); | int i = BM_elem_index_get(f); | ||||
| BLI_assert(i != -1); | BLI_assert(i != -1); | ||||
| BMLoop *l_iter, *l_first; | BMLoop *l_iter, *l_first; | ||||
| l_iter = l_first = BM_FACE_FIRST_LOOP(f); | l_iter = l_first = BM_FACE_FIRST_LOOP(f); | ||||
| do { | do { | ||||
| if (BM_elem_flag_test(l_iter->e, BM_ELEM_TAG)) { | if (BM_elem_flag_test(l_iter->e, BM_ELEM_TAG)) { | ||||
| Show All 32 Lines | |||||
| } | } | ||||
| bool EDBM_select_interior_faces(BMEditMesh *em) | bool EDBM_select_interior_faces(BMEditMesh *em) | ||||
| { | { | ||||
| BMesh *bm = em->bm; | BMesh *bm = em->bm; | ||||
| BMIter iter; | BMIter iter; | ||||
| bool changed = false; | bool changed = false; | ||||
| float *edge_lengths = MEM_mallocN(sizeof(*edge_lengths) * bm->totedge, __func__); | float *edge_lengths = static_cast<float *>( | ||||
| MEM_mallocN(sizeof(*edge_lengths) * bm->totedge, __func__)); | |||||
| { | { | ||||
| bool has_nonmanifold = false; | bool has_nonmanifold = false; | ||||
| BMEdge *e; | BMEdge *e; | ||||
| int i; | int i; | ||||
| BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) { | BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) { | ||||
| const bool is_over = BM_edge_face_count_is_over(e, 2); | const bool is_over = BM_edge_face_count_is_over(e, 2); | ||||
| if (is_over) { | if (is_over) { | ||||
| Show All 12 Lines | float *edge_lengths = static_cast<float *>( | ||||
| if (has_nonmanifold == false) { | if (has_nonmanifold == false) { | ||||
| MEM_freeN(edge_lengths); | MEM_freeN(edge_lengths); | ||||
| return false; | return false; | ||||
| } | } | ||||
| } | } | ||||
| /* group vars */ | /* group vars */ | ||||
| int *fgroup_array; | |||||
| int(*fgroup_index)[2]; | int(*fgroup_index)[2]; | ||||
| int fgroup_len; | int fgroup_len; | ||||
| fgroup_array = MEM_mallocN(sizeof(*fgroup_array) * bm->totface, __func__); | int *fgroup_array = static_cast<int *>( | ||||
| MEM_mallocN(sizeof(*fgroup_array) * bm->totface, __func__)); | |||||
| fgroup_len = BM_mesh_calc_face_groups( | fgroup_len = BM_mesh_calc_face_groups( | ||||
| bm, fgroup_array, &fgroup_index, bm_interior_loop_filter_fn, NULL, NULL, 0, BM_EDGE); | bm, fgroup_array, &fgroup_index, bm_interior_loop_filter_fn, nullptr, nullptr, 0, BM_EDGE); | ||||
| int *fgroup_recalc_stack = MEM_mallocN(sizeof(*fgroup_recalc_stack) * fgroup_len, __func__); | int *fgroup_recalc_stack = static_cast<int *>( | ||||
| MEM_mallocN(sizeof(*fgroup_recalc_stack) * fgroup_len, __func__)); | |||||
| STACK_DECLARE(fgroup_recalc_stack); | STACK_DECLARE(fgroup_recalc_stack); | ||||
| STACK_INIT(fgroup_recalc_stack, fgroup_len); | STACK_INIT(fgroup_recalc_stack, fgroup_len); | ||||
| BM_mesh_elem_table_ensure(bm, BM_FACE); | BM_mesh_elem_table_ensure(bm, BM_FACE); | ||||
| { | { | ||||
| 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) { | ||||
| BM_elem_index_set(f, -1); /* set_dirty! */ | BM_elem_index_set(f, -1); /* set_dirty! */ | ||||
| } | } | ||||
| } | } | ||||
| bm->elem_index_dirty |= BM_FACE; | bm->elem_index_dirty |= BM_FACE; | ||||
| ListBase *fgroup_listbase = MEM_callocN(sizeof(*fgroup_listbase) * fgroup_len, __func__); | ListBase *fgroup_listbase = static_cast<ListBase *>( | ||||
| struct BMFaceLink *f_link_array = MEM_callocN(sizeof(*f_link_array) * bm->totface, __func__); | MEM_callocN(sizeof(*fgroup_listbase) * fgroup_len, __func__)); | ||||
| BMFaceLink *f_link_array = static_cast<BMFaceLink *>( | |||||
| MEM_callocN(sizeof(*f_link_array) * bm->totface, __func__)); | |||||
| for (int i = 0; i < fgroup_len; i++) { | for (int i = 0; i < fgroup_len; i++) { | ||||
| const int fg_sta = fgroup_index[i][0]; | const int fg_sta = fgroup_index[i][0]; | ||||
| const int fg_len = fgroup_index[i][1]; | const int fg_len = fgroup_index[i][1]; | ||||
| for (int j = 0; j < fg_len; j++) { | for (int j = 0; j < fg_len; j++) { | ||||
| const int face_index = fgroup_array[fg_sta + j]; | const int face_index = fgroup_array[fg_sta + j]; | ||||
| BMFace *f = BM_face_at_index(bm, face_index); | BMFace *f = BM_face_at_index(bm, face_index); | ||||
| BM_elem_index_set(f, i); | BM_elem_index_set(f, i); | ||||
| struct BMFaceLink *f_link = &f_link_array[face_index]; | BMFaceLink *f_link = &f_link_array[face_index]; | ||||
| f_link->face = f; | f_link->face = f; | ||||
| f_link->area = BM_face_calc_area(f); | f_link->area = BM_face_calc_area(f); | ||||
| BLI_addtail(&fgroup_listbase[i], f_link); | BLI_addtail(&fgroup_listbase[i], f_link); | ||||
| } | } | ||||
| } | } | ||||
| MEM_freeN(fgroup_array); | MEM_freeN(fgroup_array); | ||||
| MEM_freeN(fgroup_index); | MEM_freeN(fgroup_index); | ||||
| Heap *fgroup_heap = BLI_heap_new_ex(fgroup_len); | Heap *fgroup_heap = BLI_heap_new_ex(fgroup_len); | ||||
| HeapNode **fgroup_table = MEM_mallocN(sizeof(*fgroup_table) * fgroup_len, __func__); | HeapNode **fgroup_table = static_cast<HeapNode **>( | ||||
| bool *fgroup_dirty = MEM_callocN(sizeof(*fgroup_dirty) * fgroup_len, __func__); | MEM_mallocN(sizeof(*fgroup_table) * fgroup_len, __func__)); | ||||
| bool *fgroup_dirty = static_cast<bool *>( | |||||
| MEM_callocN(sizeof(*fgroup_dirty) * fgroup_len, __func__)); | |||||
| for (int i = 0; i < fgroup_len; i++) { | for (int i = 0; i < fgroup_len; i++) { | ||||
| const float cost = bm_interior_face_group_calc_cost(&fgroup_listbase[i], edge_lengths); | const float cost = bm_interior_face_group_calc_cost(&fgroup_listbase[i], edge_lengths); | ||||
| if (cost != FLT_MAX) { | if (cost != FLT_MAX) { | ||||
| fgroup_table[i] = BLI_heap_insert(fgroup_heap, -cost, POINTER_FROM_INT(i)); | fgroup_table[i] = BLI_heap_insert(fgroup_heap, -cost, POINTER_FROM_INT(i)); | ||||
| } | } | ||||
| else { | else { | ||||
| fgroup_table[i] = NULL; | fgroup_table[i] = nullptr; | ||||
| } | } | ||||
| } | } | ||||
| /* Avoid re-running cost calculations for large face-groups which will end up forming the | /* Avoid re-running cost calculations for large face-groups which will end up forming the | ||||
| * outer shell and not be considered interior. | * outer shell and not be considered interior. | ||||
| * As these face groups become increasingly bigger - their chance of being considered | * As these face groups become increasingly bigger - their chance of being considered | ||||
| * interior reduces as does the time to calculate their cost. | * interior reduces as does the time to calculate their cost. | ||||
| * | * | ||||
| Show All 13 Lines | while (!BLI_heap_is_empty(fgroup_heap)) { | ||||
| if (cost != FLT_MAX) { | if (cost != FLT_MAX) { | ||||
| /* The cost may have improves (we may be able to skip this), | /* The cost may have improves (we may be able to skip this), | ||||
| * however the cost should _never_ make this a choice. */ | * however the cost should _never_ make this a choice. */ | ||||
| BLI_assert(-BLI_heap_node_value(node_min) >= cost); | BLI_assert(-BLI_heap_node_value(node_min) >= cost); | ||||
| BLI_heap_node_value_update(fgroup_heap, fgroup_table[i], -cost); | BLI_heap_node_value_update(fgroup_heap, fgroup_table[i], -cost); | ||||
| } | } | ||||
| else { | else { | ||||
| BLI_heap_remove(fgroup_heap, fgroup_table[i]); | BLI_heap_remove(fgroup_heap, fgroup_table[i]); | ||||
| fgroup_table[i] = NULL; | fgroup_table[i] = nullptr; | ||||
| } | } | ||||
| fgroup_dirty[i] = false; | fgroup_dirty[i] = false; | ||||
| } | } | ||||
| else { | else { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| #endif | #endif | ||||
| if (BLI_heap_is_empty(fgroup_heap)) { | if (BLI_heap_is_empty(fgroup_heap)) { | ||||
| break; | break; | ||||
| } | } | ||||
| const int i_min = POINTER_AS_INT(BLI_heap_pop_min(fgroup_heap)); | const int i_min = POINTER_AS_INT(BLI_heap_pop_min(fgroup_heap)); | ||||
| BLI_assert(fgroup_table[i_min] != NULL); | BLI_assert(fgroup_table[i_min] != nullptr); | ||||
| BLI_assert(fgroup_dirty[i_min] == false); | BLI_assert(fgroup_dirty[i_min] == false); | ||||
| fgroup_table[i_min] = NULL; | fgroup_table[i_min] = nullptr; | ||||
| changed = true; | changed = true; | ||||
| struct BMFaceLink *f_link; | BMFaceLink *f_link; | ||||
| while ((f_link = BLI_pophead(&fgroup_listbase[i_min]))) { | while ((f_link = static_cast<BMFaceLink *>(BLI_pophead(&fgroup_listbase[i_min])))) { | ||||
| BMFace *f = f_link->face; | BMFace *f = f_link->face; | ||||
| BM_face_select_set(bm, f, true); | BM_face_select_set(bm, f, true); | ||||
| BM_elem_index_set(f, -1); /* set-dirty */ | BM_elem_index_set(f, -1); /* set-dirty */ | ||||
| BMLoop *l_iter, *l_first; | BMLoop *l_iter, *l_first; | ||||
| /* Loop over edges face edges, merging groups which are no longer separated | /* Loop over edges face edges, merging groups which are no longer separated | ||||
| * by non-manifold edges (when manifold check ignores faces from this group). */ | * by non-manifold edges (when manifold check ignores faces from this group). */ | ||||
| Show All 9 Lines | while ((f_link = static_cast<BMFaceLink *>(BLI_pophead(&fgroup_listbase[i_min])))) { | ||||
| /* Only for predictable results that don't depend on the order of radial loops, | /* Only for predictable results that don't depend on the order of radial loops, | ||||
| * not essential. */ | * not essential. */ | ||||
| if (i_a > i_b) { | if (i_a > i_b) { | ||||
| SWAP(int, i_a, i_b); | SWAP(int, i_a, i_b); | ||||
| } | } | ||||
| /* Merge the groups. */ | /* Merge the groups. */ | ||||
| LISTBASE_FOREACH (LinkData *, n, &fgroup_listbase[i_b]) { | LISTBASE_FOREACH (LinkData *, n, &fgroup_listbase[i_b]) { | ||||
| BMFace *f_iter = n->data; | BMFace *f_iter = static_cast<BMFace *>(n->data); | ||||
| BM_elem_index_set(f_iter, i_a); | BM_elem_index_set(f_iter, i_a); | ||||
| } | } | ||||
| BLI_movelisttolist(&fgroup_listbase[i_a], &fgroup_listbase[i_b]); | BLI_movelisttolist(&fgroup_listbase[i_a], &fgroup_listbase[i_b]); | ||||
| /* This may have been added to 'fgroup_recalc_stack', instead of removing it, | /* This may have been added to 'fgroup_recalc_stack', instead of removing it, | ||||
| * just check the heap node isn't NULL before recalculating. */ | * just check the heap node isn't nullptr before recalculating. */ | ||||
| BLI_heap_remove(fgroup_heap, fgroup_table[i_b]); | BLI_heap_remove(fgroup_heap, fgroup_table[i_b]); | ||||
| fgroup_table[i_b] = NULL; | fgroup_table[i_b] = nullptr; | ||||
| /* Keep the dirty flag as-is for 'i_b', because it may be in the 'fgroup_recalc_stack' | /* Keep the dirty flag as-is for 'i_b', because it may be in the 'fgroup_recalc_stack' | ||||
| * and we don't want to add it again. | * and we don't want to add it again. | ||||
| * Instead rely on the 'fgroup_table[i_b]' being NULL as a secondary check. */ | * Instead rely on the 'fgroup_table[i_b]' being nullptr as a secondary check. */ | ||||
| if (fgroup_dirty[i_a] == false) { | if (fgroup_dirty[i_a] == false) { | ||||
| BLI_assert(fgroup_table[i_a] != NULL); | BLI_assert(fgroup_table[i_a] != nullptr); | ||||
| STACK_PUSH(fgroup_recalc_stack, i_a); | STACK_PUSH(fgroup_recalc_stack, i_a); | ||||
| fgroup_dirty[i_a] = true; | fgroup_dirty[i_a] = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Mark all connected groups for re-calculation. */ | /* Mark all connected groups for re-calculation. */ | ||||
| BMLoop *l_radial_iter = l_iter->radial_next; | BMLoop *l_radial_iter = l_iter->radial_next; | ||||
| if (l_radial_iter != l_iter) { | if (l_radial_iter != l_iter) { | ||||
| do { | do { | ||||
| int i_other = BM_elem_index_get(l_radial_iter->f); | int i_other = BM_elem_index_get(l_radial_iter->f); | ||||
| if (!ELEM(i_other, -1, i_min)) { | if (!ELEM(i_other, -1, i_min)) { | ||||
| if ((fgroup_table[i_other] != NULL) && (fgroup_dirty[i_other] == false)) { | if ((fgroup_table[i_other] != nullptr) && (fgroup_dirty[i_other] == false)) { | ||||
| #if !defined(USE_DELAY_FACE_GROUP_COST_CALC) | #if !defined(USE_DELAY_FACE_GROUP_COST_CALC) | ||||
| STACK_PUSH(fgroup_recalc_stack, i_other); | STACK_PUSH(fgroup_recalc_stack, i_other); | ||||
| #endif | #endif | ||||
| fgroup_dirty[i_other] = true; | fgroup_dirty[i_other] = true; | ||||
| } | } | ||||
| } | } | ||||
| } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter); | } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter); | ||||
| } | } | ||||
| } while ((l_iter = l_iter->next) != l_first); | } while ((l_iter = l_iter->next) != l_first); | ||||
| } | } | ||||
| for (int index = 0; index < STACK_SIZE(fgroup_recalc_stack); index++) { | for (int index = 0; index < STACK_SIZE(fgroup_recalc_stack); index++) { | ||||
| const int i = fgroup_recalc_stack[index]; | const int i = fgroup_recalc_stack[index]; | ||||
| if (fgroup_table[i] != NULL && fgroup_dirty[i] == true) { | if (fgroup_table[i] != nullptr && fgroup_dirty[i] == true) { | ||||
| /* First update edge tags. */ | /* First update edge tags. */ | ||||
| const float cost = bm_interior_face_group_calc_cost(&fgroup_listbase[i], edge_lengths); | const float cost = bm_interior_face_group_calc_cost(&fgroup_listbase[i], edge_lengths); | ||||
| if (cost != FLT_MAX) { | if (cost != FLT_MAX) { | ||||
| BLI_heap_node_value_update(fgroup_heap, fgroup_table[i], -cost); | BLI_heap_node_value_update(fgroup_heap, fgroup_table[i], -cost); | ||||
| } | } | ||||
| else { | else { | ||||
| BLI_heap_remove(fgroup_heap, fgroup_table[i]); | BLI_heap_remove(fgroup_heap, fgroup_table[i]); | ||||
| fgroup_table[i] = NULL; | fgroup_table[i] = nullptr; | ||||
| } | } | ||||
| } | } | ||||
| fgroup_dirty[i] = false; | fgroup_dirty[i] = false; | ||||
| } | } | ||||
| STACK_CLEAR(fgroup_recalc_stack); | STACK_CLEAR(fgroup_recalc_stack); | ||||
| } | } | ||||
| MEM_freeN(edge_lengths); | MEM_freeN(edge_lengths); | ||||
| MEM_freeN(f_link_array); | MEM_freeN(f_link_array); | ||||
| MEM_freeN(fgroup_listbase); | MEM_freeN(fgroup_listbase); | ||||
| MEM_freeN(fgroup_recalc_stack); | MEM_freeN(fgroup_recalc_stack); | ||||
| MEM_freeN(fgroup_table); | MEM_freeN(fgroup_table); | ||||
| MEM_freeN(fgroup_dirty); | MEM_freeN(fgroup_dirty); | ||||
| BLI_heap_free(fgroup_heap, NULL); | BLI_heap_free(fgroup_heap, nullptr); | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Select Linked Operator | /** \name Select Linked Operator | ||||
| * | * | ||||
| * Support delimiting on different edge properties. | * Support delimiting on different edge properties. | ||||
| * \{ */ | * \{ */ | ||||
| /* so we can have last-used default depend on selection mode (rare exception!) */ | /* so we can have last-used default depend on selection mode (rare exception!) */ | ||||
| #define USE_LINKED_SELECT_DEFAULT_HACK | #define USE_LINKED_SELECT_DEFAULT_HACK | ||||
| struct DelimitData { | struct DelimitData { | ||||
| int cd_loop_type; | int cd_loop_type; | ||||
| int cd_loop_offset; | int cd_loop_offset; | ||||
| }; | }; | ||||
| static bool select_linked_delimit_test(BMEdge *e, | static bool select_linked_delimit_test(BMEdge *e, int delimit, const DelimitData *delimit_data) | ||||
| int delimit, | |||||
| const struct DelimitData *delimit_data) | |||||
| { | { | ||||
| BLI_assert(delimit); | BLI_assert(delimit); | ||||
| if (delimit & BMO_DELIM_SEAM) { | if (delimit & BMO_DELIM_SEAM) { | ||||
| if (BM_elem_flag_test(e, BM_ELEM_SEAM)) { | if (BM_elem_flag_test(e, BM_ELEM_SEAM)) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | if ((*delimit) & BMO_DELIM_UV) { | ||||
| if (!CustomData_has_layer(&bm->ldata, CD_MLOOPUV)) { | if (!CustomData_has_layer(&bm->ldata, CD_MLOOPUV)) { | ||||
| (*delimit) &= ~BMO_DELIM_UV; | (*delimit) &= ~BMO_DELIM_UV; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void select_linked_delimit_begin(BMesh *bm, int delimit) | static void select_linked_delimit_begin(BMesh *bm, int delimit) | ||||
| { | { | ||||
| struct DelimitData delimit_data = {0}; | DelimitData delimit_data = {0}; | ||||
| if (delimit & BMO_DELIM_UV) { | if (delimit & BMO_DELIM_UV) { | ||||
| delimit_data.cd_loop_type = CD_MLOOPUV; | delimit_data.cd_loop_type = CD_MLOOPUV; | ||||
| delimit_data.cd_loop_offset = CustomData_get_offset(&bm->ldata, delimit_data.cd_loop_type); | delimit_data.cd_loop_offset = CustomData_get_offset(&bm->ldata, delimit_data.cd_loop_type); | ||||
| if (delimit_data.cd_loop_offset == -1) { | if (delimit_data.cd_loop_offset == -1) { | ||||
| delimit &= ~BMO_DELIM_UV; | delimit &= ~BMO_DELIM_UV; | ||||
| } | } | ||||
| } | } | ||||
| /* grr, shouldn't need to alloc BMO flags here */ | /* Shouldn't need to allocated BMO flags here (sigh). */ | ||||
| BM_mesh_elem_toolflags_ensure(bm); | BM_mesh_elem_toolflags_ensure(bm); | ||||
| { | { | ||||
| BMIter iter; | BMIter iter; | ||||
| BMEdge *e; | BMEdge *e; | ||||
| BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { | BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { | ||||
| const bool is_walk_ok = (select_linked_delimit_test(e, delimit, &delimit_data) == false); | const bool is_walk_ok = (select_linked_delimit_test(e, delimit, &delimit_data) == false); | ||||
| ▲ Show 20 Lines • Show All 204 Lines • ▼ Show 20 Lines | else { | ||||
| BMW_end(&walker); | BMW_end(&walker); | ||||
| } | } | ||||
| if (delimit) { | if (delimit) { | ||||
| select_linked_delimit_end(em); | select_linked_delimit_end(em); | ||||
| } | } | ||||
| DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); | DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | ||||
| } | } | ||||
| MEM_freeN(objects); | MEM_freeN(objects); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 147 Lines • ▼ Show 20 Lines | static void edbm_select_linked_pick_ex(BMEditMesh *em, BMElem *ele, bool sel, int delimit) | ||||
| if (delimit) { | if (delimit) { | ||||
| select_linked_delimit_end(em); | select_linked_delimit_end(em); | ||||
| } | } | ||||
| } | } | ||||
| static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) | static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| { | { | ||||
| ViewContext vc; | ViewContext vc; | ||||
| Base *basact = NULL; | Base *basact = nullptr; | ||||
| BMVert *eve; | BMVert *eve; | ||||
| BMEdge *eed; | BMEdge *eed; | ||||
| BMFace *efa; | BMFace *efa; | ||||
| const bool sel = !RNA_boolean_get(op->ptr, "deselect"); | const bool sel = !RNA_boolean_get(op->ptr, "deselect"); | ||||
| int index; | int index; | ||||
| if (RNA_struct_property_is_set(op->ptr, "index")) { | if (RNA_struct_property_is_set(op->ptr, "index")) { | ||||
| return edbm_select_linked_pick_exec(C, op); | return edbm_select_linked_pick_exec(C, op); | ||||
| ▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | /* To support redo. */ | ||||
| BM_mesh_elem_index_ensure(bm, ele->head.htype); | BM_mesh_elem_index_ensure(bm, ele->head.htype); | ||||
| int object_index; | int object_index; | ||||
| index = EDBM_elem_to_index_any_multi(vc.scene, vc.view_layer, em, ele, &object_index); | index = EDBM_elem_to_index_any_multi(vc.scene, vc.view_layer, em, ele, &object_index); | ||||
| BLI_assert(object_index >= 0); | BLI_assert(object_index >= 0); | ||||
| RNA_int_set(op->ptr, "object_index", object_index); | RNA_int_set(op->ptr, "object_index", object_index); | ||||
| RNA_int_set(op->ptr, "index", index); | RNA_int_set(op->ptr, "index", index); | ||||
| } | } | ||||
| DEG_id_tag_update(basact->object->data, ID_RECALC_SELECT); | DEG_id_tag_update(static_cast<ID *>(basact->object->data), ID_RECALC_SELECT); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, basact->object->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, basact->object->data); | ||||
| MEM_freeN(bases); | MEM_freeN(bases); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op) | static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| Object *obedit = NULL; | Object *obedit = nullptr; | ||||
| BMElem *ele; | BMElem *ele; | ||||
| { | { | ||||
| const Scene *scene = CTX_data_scene(C); | const Scene *scene = CTX_data_scene(C); | ||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| /* Intentionally wrap negative values so the lookup fails. */ | /* Intentionally wrap negative values so the lookup fails. */ | ||||
| const uint object_index = (uint)RNA_int_get(op->ptr, "object_index"); | const uint object_index = uint(RNA_int_get(op->ptr, "object_index")); | ||||
| const uint index = (uint)RNA_int_get(op->ptr, "index"); | const uint index = uint(RNA_int_get(op->ptr, "index")); | ||||
| ele = EDBM_elem_from_index_any_multi(scene, view_layer, object_index, index, &obedit); | ele = EDBM_elem_from_index_any_multi(scene, view_layer, object_index, index, &obedit); | ||||
| } | } | ||||
| if (ele == NULL) { | if (ele == nullptr) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| const bool sel = !RNA_boolean_get(op->ptr, "deselect"); | const bool sel = !RNA_boolean_get(op->ptr, "deselect"); | ||||
| #ifdef USE_LINKED_SELECT_DEFAULT_HACK | #ifdef USE_LINKED_SELECT_DEFAULT_HACK | ||||
| int delimit = select_linked_delimit_default_from_op(op, em->selectmode); | int delimit = select_linked_delimit_default_from_op(op, em->selectmode); | ||||
| #else | #else | ||||
| int delimit = RNA_enum_get(op->ptr, "delimit"); | int delimit = RNA_enum_get(op->ptr, "delimit"); | ||||
| #endif | #endif | ||||
| edbm_select_linked_pick_ex(em, ele, sel, delimit); | edbm_select_linked_pick_ex(em, ele, sel, delimit); | ||||
| DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); | DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void MESH_OT_select_linked_pick(wmOperatorType *ot) | void MESH_OT_select_linked_pick(wmOperatorType *ot) | ||||
| { | { | ||||
| PropertyRNA *prop; | PropertyRNA *prop; | ||||
| Show All 19 Lines | prop = RNA_def_enum_flag(ot->srna, | ||||
| "Delimit", | "Delimit", | ||||
| "Delimit selected region"); | "Delimit selected region"); | ||||
| #ifdef USE_LINKED_SELECT_DEFAULT_HACK | #ifdef USE_LINKED_SELECT_DEFAULT_HACK | ||||
| RNA_def_property_flag(prop, PROP_SKIP_SAVE); | RNA_def_property_flag(prop, PROP_SKIP_SAVE); | ||||
| #endif | #endif | ||||
| /* use for redo */ | /* use for redo */ | ||||
| prop = RNA_def_int(ot->srna, "object_index", -1, -1, INT_MAX, "", "", 0, INT_MAX); | prop = RNA_def_int(ot->srna, "object_index", -1, -1, INT_MAX, "", "", 0, INT_MAX); | ||||
| RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); | RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN | PROP_SKIP_SAVE)); | ||||
| prop = RNA_def_int(ot->srna, "index", -1, -1, INT_MAX, "", "", 0, INT_MAX); | prop = RNA_def_int(ot->srna, "index", -1, -1, INT_MAX, "", "", 0, INT_MAX); | ||||
| RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); | RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN | PROP_SKIP_SAVE)); | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Select Face by Sides Operator | /** \name Select Face by Sides Operator | ||||
| * \{ */ | * \{ */ | ||||
| ▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (select) { | if (select) { | ||||
| BM_face_select_set(em->bm, efa, true); | BM_face_select_set(em->bm, efa, true); | ||||
| } | } | ||||
| } | } | ||||
| EDBM_selectmode_flush(em); | EDBM_selectmode_flush(em); | ||||
| DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); | DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | ||||
| } | } | ||||
| MEM_freeN(objects); | MEM_freeN(objects); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void MESH_OT_select_face_by_sides(wmOperatorType *ot) | void MESH_OT_select_face_by_sides(wmOperatorType *ot) | ||||
| { | { | ||||
| static const EnumPropertyItem type_items[] = { | static const EnumPropertyItem type_items[] = { | ||||
| {0, "LESS", 0, "Less Than", ""}, | {0, "LESS", 0, "Less Than", ""}, | ||||
| {1, "EQUAL", 0, "Equal To", ""}, | {1, "EQUAL", 0, "Equal To", ""}, | ||||
| {2, "GREATER", 0, "Greater Than", ""}, | {2, "GREATER", 0, "Greater Than", ""}, | ||||
| {3, "NOTEQUAL", 0, "Not Equal To", ""}, | {3, "NOTEQUAL", 0, "Not Equal To", ""}, | ||||
| {0, NULL, 0, NULL, NULL}, | {0, nullptr, 0, nullptr, nullptr}, | ||||
| }; | }; | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Select Faces by Sides"; | ot->name = "Select Faces by Sides"; | ||||
| ot->description = "Select vertices or faces by the number of polygon sides"; | ot->description = "Select vertices or faces by the number of polygon sides"; | ||||
| ot->idname = "MESH_OT_select_face_by_sides"; | ot->idname = "MESH_OT_select_face_by_sides"; | ||||
| /* api callbacks */ | /* api callbacks */ | ||||
| ▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | if (em->selectmode & SCE_SELECT_FACE) { | ||||
| if (is_loose) { | if (is_loose) { | ||||
| BM_face_select_set(bm, efa, true); | BM_face_select_set(bm, efa, true); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| EDBM_selectmode_flush(em); | EDBM_selectmode_flush(em); | ||||
| DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); | DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | ||||
| } | } | ||||
| MEM_freeN(objects); | MEM_freeN(objects); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| if (em->bm->totvertsel == 0) { | if (em->bm->totvertsel == 0) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| int tot_mirr_iter = 0, tot_fail_iter = 0; | int tot_mirr_iter = 0, tot_fail_iter = 0; | ||||
| for (int axis = 0; axis < 3; axis++) { | for (int axis = 0; axis < 3; axis++) { | ||||
| if ((1 << axis) & axis_flag) { | if ((1 << axis) & axis_flag) { | ||||
| EDBM_select_mirrored(em, obedit->data, axis, extend, &tot_mirr_iter, &tot_fail_iter); | EDBM_select_mirrored(em, | ||||
| static_cast<const Mesh *>(obedit->data), | |||||
| axis, | |||||
| extend, | |||||
| &tot_mirr_iter, | |||||
| &tot_fail_iter); | |||||
| } | } | ||||
| } | } | ||||
| if (tot_mirr_iter) { | if (tot_mirr_iter) { | ||||
| EDBM_selectmode_flush(em); | EDBM_selectmode_flush(em); | ||||
| DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); | DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | ||||
| } | } | ||||
| tot_fail += tot_fail_iter; | tot_fail += tot_fail_iter; | ||||
| tot_mirr += tot_mirr_iter; | tot_mirr += tot_mirr_iter; | ||||
| } | } | ||||
| MEM_freeN(objects); | MEM_freeN(objects); | ||||
| ▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| BMesh *bm = em->bm; | BMesh *bm = em->bm; | ||||
| if ((bm->totvertsel == 0) && (bm->totedgesel == 0) && (bm->totfacesel == 0)) { | if ((bm->totvertsel == 0) && (bm->totedgesel == 0) && (bm->totfacesel == 0)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| EDBM_select_more(em, use_face_step); | EDBM_select_more(em, use_face_step); | ||||
| DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); | DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | ||||
| } | } | ||||
| MEM_freeN(objects); | MEM_freeN(objects); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void MESH_OT_select_more(wmOperatorType *ot) | void MESH_OT_select_more(wmOperatorType *ot) | ||||
| Show All 34 Lines | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| BMesh *bm = em->bm; | BMesh *bm = em->bm; | ||||
| if ((bm->totvertsel == 0) && (bm->totedgesel == 0) && (bm->totfacesel == 0)) { | if ((bm->totvertsel == 0) && (bm->totedgesel == 0) && (bm->totfacesel == 0)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| EDBM_select_less(em, use_face_step); | EDBM_select_less(em, use_face_step); | ||||
| DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); | DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | ||||
| } | } | ||||
| MEM_freeN(objects); | MEM_freeN(objects); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void MESH_OT_select_less(wmOperatorType *ot) | void MESH_OT_select_less(wmOperatorType *ot) | ||||
| Show All 40 Lines | static bool bm_edge_is_select_isolated(BMEdge *e) | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| /* Walk all reachable elements of the same type as h_act in breadth-first | /* Walk all reachable elements of the same type as h_act in breadth-first | ||||
| * order, starting from h_act. Deselects elements if the depth when they | * order, starting from h_act. Deselects elements if the depth when they | ||||
| * are reached is not a multiple of "nth". */ | * are reached is not a multiple of "nth". */ | ||||
| static void walker_deselect_nth(BMEditMesh *em, | static void walker_deselect_nth(BMEditMesh *em, | ||||
| const struct CheckerIntervalParams *op_params, | const CheckerIntervalParams *op_params, | ||||
| BMHeader *h_act) | BMHeader *h_act) | ||||
| { | { | ||||
| BMElem *ele; | BMElem *ele; | ||||
| BMesh *bm = em->bm; | BMesh *bm = em->bm; | ||||
| BMWalker walker; | BMWalker walker; | ||||
| BMIter iter; | BMIter iter; | ||||
| int walktype = 0, itertype = 0, flushtype = 0; | int walktype = 0, itertype = 0, flushtype = 0; | ||||
| short mask_vert = 0, mask_edge = 0, mask_face = 0; | short mask_vert = 0, mask_edge = 0, mask_face = 0; | ||||
| /* No active element from which to start - nothing to do */ | /* No active element from which to start - nothing to do */ | ||||
| if (h_act == NULL) { | if (h_act == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* Determine which type of iter, walker, and select flush to use | /* Determine which type of iter, walker, and select flush to use | ||||
| * based on type of the elements being deselected */ | * based on type of the elements being deselected */ | ||||
| switch (h_act->htype) { | switch (h_act->htype) { | ||||
| case BM_VERT: | case BM_VERT: | ||||
| itertype = BM_VERTS_OF_MESH; | itertype = BM_VERTS_OF_MESH; | ||||
| Show All 12 Lines | switch (h_act->htype) { | ||||
| case BM_FACE: | case BM_FACE: | ||||
| itertype = BM_FACES_OF_MESH; | itertype = BM_FACES_OF_MESH; | ||||
| walktype = BMW_ISLAND; | walktype = BMW_ISLAND; | ||||
| flushtype = SCE_SELECT_FACE; | flushtype = SCE_SELECT_FACE; | ||||
| mask_face = BMO_ELE_TAG; | mask_face = BMO_ELE_TAG; | ||||
| break; | break; | ||||
| } | } | ||||
| /* grr, shouldn't need to alloc BMO flags here */ | /* Shouldn't need to allocate BMO flags here (sigh). */ | ||||
| BM_mesh_elem_toolflags_ensure(bm); | BM_mesh_elem_toolflags_ensure(bm); | ||||
| /* Walker restrictions uses BMO flags, not header flags, | /* Walker restrictions uses BMO flags, not header flags, | ||||
| * so transfer BM_ELEM_SELECT from HFlags onto a BMO flag layer. */ | * so transfer BM_ELEM_SELECT from HFlags onto a BMO flag layer. */ | ||||
| BMO_push(bm, NULL); | BMO_push(bm, nullptr); | ||||
| BM_ITER_MESH (ele, &iter, bm, itertype) { | BM_ITER_MESH (ele, &iter, bm, itertype) { | ||||
| if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) { | if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) { | ||||
| BMO_elem_flag_enable(bm, (BMElemF *)ele, BMO_ELE_TAG); | BMO_elem_flag_enable(bm, (BMElemF *)ele, BMO_ELE_TAG); | ||||
| } | } | ||||
| } | } | ||||
| /* Walk over selected elements starting at active */ | /* Walk over selected elements starting at active */ | ||||
| BMW_init(&walker, | BMW_init(&walker, | ||||
| bm, | bm, | ||||
| walktype, | walktype, | ||||
| mask_vert, | mask_vert, | ||||
| mask_edge, | mask_edge, | ||||
| mask_face, | mask_face, | ||||
| BMW_FLAG_NOP, /* don't use BMW_FLAG_TEST_HIDDEN here since we want to desel all */ | BMW_FLAG_NOP, /* Don't use #BMW_FLAG_TEST_HIDDEN here since we want to deselect all. */ | ||||
| BMW_NIL_LAY); | BMW_NIL_LAY); | ||||
| /* use tag to avoid touching the same verts twice */ | /* use tag to avoid touching the same verts twice */ | ||||
| BM_ITER_MESH (ele, &iter, bm, itertype) { | BM_ITER_MESH (ele, &iter, bm, itertype) { | ||||
| BM_elem_flag_disable(ele, BM_ELEM_TAG); | BM_elem_flag_disable(ele, BM_ELEM_TAG); | ||||
| } | } | ||||
| BLI_assert(walker.order == BMW_BREADTH_FIRST); | BLI_assert(walker.order == BMW_BREADTH_FIRST); | ||||
| for (ele = BMW_begin(&walker, h_act); ele != NULL; ele = BMW_step(&walker)) { | for (ele = static_cast<BMElem *>(BMW_begin(&walker, h_act)); ele != nullptr; | ||||
| ele = static_cast<BMElem *>(BMW_step(&walker))) { | |||||
| if (!BM_elem_flag_test(ele, BM_ELEM_TAG)) { | if (!BM_elem_flag_test(ele, BM_ELEM_TAG)) { | ||||
| /* Deselect elements that aren't at "nth" depth from active */ | /* Deselect elements that aren't at "nth" depth from active */ | ||||
| const int depth = BMW_current_depth(&walker) - 1; | const int depth = BMW_current_depth(&walker) - 1; | ||||
| if (!WM_operator_properties_checker_interval_test(op_params, depth)) { | if (!WM_operator_properties_checker_interval_test(op_params, depth)) { | ||||
| BM_elem_select_set(bm, ele, false); | BM_elem_select_set(bm, ele, false); | ||||
| } | } | ||||
| BM_elem_flag_enable(ele, BM_ELEM_TAG); | BM_elem_flag_enable(ele, BM_ELEM_TAG); | ||||
| } | } | ||||
| } | } | ||||
| BMW_end(&walker); | BMW_end(&walker); | ||||
| BMO_pop(bm); | BMO_pop(bm); | ||||
| /* Flush selection up */ | /* Flush selection up */ | ||||
| EDBM_selectmode_flush_ex(em, flushtype); | EDBM_selectmode_flush_ex(em, flushtype); | ||||
| } | } | ||||
| static void deselect_nth_active(BMEditMesh *em, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa) | static void deselect_nth_active(BMEditMesh *em, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa) | ||||
| { | { | ||||
| BMIter iter; | BMIter iter; | ||||
| BMElem *ele; | BMElem *ele; | ||||
| *r_eve = NULL; | *r_eve = nullptr; | ||||
| *r_eed = NULL; | *r_eed = nullptr; | ||||
| *r_efa = NULL; | *r_efa = nullptr; | ||||
| EDBM_selectmode_flush(em); | EDBM_selectmode_flush(em); | ||||
| ele = BM_mesh_active_elem_get(em->bm); | ele = BM_mesh_active_elem_get(em->bm); | ||||
| if (ele && BM_elem_flag_test(ele, BM_ELEM_SELECT)) { | if (ele && BM_elem_flag_test(ele, BM_ELEM_SELECT)) { | ||||
| switch (ele->head.htype) { | switch (ele->head.htype) { | ||||
| case BM_VERT: | case BM_VERT: | ||||
| *r_eve = (BMVert *)ele; | *r_eve = (BMVert *)ele; | ||||
| Show All 29 Lines | else if (em->selectmode & SCE_SELECT_FACE) { | ||||
| BMFace *f = BM_mesh_active_face_get(em->bm, true, false); | BMFace *f = BM_mesh_active_face_get(em->bm, true, false); | ||||
| if (f && BM_elem_flag_test(f, BM_ELEM_SELECT)) { | if (f && BM_elem_flag_test(f, BM_ELEM_SELECT)) { | ||||
| *r_efa = f; | *r_efa = f; | ||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static bool edbm_deselect_nth(BMEditMesh *em, const struct CheckerIntervalParams *op_params) | static bool edbm_deselect_nth(BMEditMesh *em, const CheckerIntervalParams *op_params) | ||||
| { | { | ||||
| BMVert *v; | BMVert *v; | ||||
| BMEdge *e; | BMEdge *e; | ||||
| BMFace *f; | BMFace *f; | ||||
| deselect_nth_active(em, &v, &e, &f); | deselect_nth_active(em, &v, &e, &f); | ||||
| if (v) { | if (v) { | ||||
| Show All 11 Lines | static bool edbm_deselect_nth(BMEditMesh *em, const CheckerIntervalParams *op_params) | ||||
| return false; | return false; | ||||
| } | } | ||||
| static int edbm_select_nth_exec(bContext *C, wmOperator *op) | static int edbm_select_nth_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| const Scene *scene = CTX_data_scene(C); | const Scene *scene = CTX_data_scene(C); | ||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| struct CheckerIntervalParams op_params; | CheckerIntervalParams op_params; | ||||
| WM_operator_properties_checker_interval_from_op(op, &op_params); | WM_operator_properties_checker_interval_from_op(op, &op_params); | ||||
| bool found_active_elt = false; | bool found_active_elt = false; | ||||
| uint objects_len = 0; | uint objects_len = 0; | ||||
| Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( | Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( | ||||
| scene, view_layer, CTX_wm_view3d(C), &objects_len); | scene, view_layer, CTX_wm_view3d(C), &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); | ||||
| if ((em->bm->totvertsel == 0) && (em->bm->totedgesel == 0) && (em->bm->totfacesel == 0)) { | if ((em->bm->totvertsel == 0) && (em->bm->totedgesel == 0) && (em->bm->totfacesel == 0)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (edbm_deselect_nth(em, &op_params) == true) { | if (edbm_deselect_nth(em, &op_params) == true) { | ||||
| found_active_elt = true; | found_active_elt = true; | ||||
| EDBM_update(obedit->data, | EDBMUpdate_Params params{}; | ||||
| &(const struct EDBMUpdate_Params){ | params.calc_looptri = false; | ||||
| .calc_looptri = false, | params.calc_normals = false; | ||||
| .calc_normals = false, | params.is_destructive = false; | ||||
| .is_destructive = false, | EDBM_update(static_cast<Mesh *>(obedit->data), ¶ms); | ||||
| }); | |||||
| } | } | ||||
| } | } | ||||
| MEM_freeN(objects); | MEM_freeN(objects); | ||||
| if (!found_active_elt) { | if (!found_active_elt) { | ||||
| BKE_report(op->reports, RPT_ERROR, "Mesh object(s) have no active vertex/edge/face"); | BKE_report(op->reports, RPT_ERROR, "Mesh object(s) have no active vertex/edge/face"); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| if ((em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0) { | if ((em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0) { | ||||
| /* Since we can't select individual edges, select faces connected to them. */ | /* Since we can't select individual edges, select faces connected to them. */ | ||||
| EDBM_selectmode_convert(em, SCE_SELECT_EDGE, SCE_SELECT_FACE); | EDBM_selectmode_convert(em, SCE_SELECT_EDGE, SCE_SELECT_FACE); | ||||
| } | } | ||||
| else { | else { | ||||
| EDBM_selectmode_flush(em); | EDBM_selectmode_flush(em); | ||||
| } | } | ||||
| DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); | DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | ||||
| } | } | ||||
| MEM_freeN(objects); | MEM_freeN(objects); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void MESH_OT_edges_select_sharp(wmOperatorType *ot) | void MESH_OT_edges_select_sharp(wmOperatorType *ot) | ||||
| Show All 11 Lines | void MESH_OT_edges_select_sharp(wmOperatorType *ot) | ||||
| /* flags */ | /* flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* props */ | /* props */ | ||||
| prop = RNA_def_float_rotation(ot->srna, | prop = RNA_def_float_rotation(ot->srna, | ||||
| "sharpness", | "sharpness", | ||||
| 0, | 0, | ||||
| NULL, | nullptr, | ||||
| DEG2RADF(0.01f), | DEG2RADF(0.01f), | ||||
| DEG2RADF(180.0f), | DEG2RADF(180.0f), | ||||
| "Sharpness", | "Sharpness", | ||||
| "", | "", | ||||
| DEG2RADF(1.0f), | DEG2RADF(1.0f), | ||||
| DEG2RADF(180.0f)); | DEG2RADF(180.0f)); | ||||
| RNA_def_property_float_default(prop, DEG2RADF(30.0f)); | RNA_def_property_float_default(prop, DEG2RADF(30.0f)); | ||||
| } | } | ||||
| Show All 17 Lines | 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); | ||||
| BMesh *bm = em->bm; | BMesh *bm = em->bm; | ||||
| if (bm->totfacesel == 0) { | if (bm->totfacesel == 0) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BLI_LINKSTACK_DECLARE(stack, BMFace *); | blender::Vector<BMFace *> stack; | ||||
| BMIter iter, liter, liter2; | BMIter iter, liter, liter2; | ||||
| BMFace *f; | BMFace *f; | ||||
| BMLoop *l, *l2; | BMLoop *l, *l2; | ||||
| BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); | BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); | ||||
| BLI_LINKSTACK_INIT(stack); | |||||
| BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { | ||||
| if ((BM_elem_flag_test(f, BM_ELEM_HIDDEN) != 0) || | if ((BM_elem_flag_test(f, BM_ELEM_HIDDEN) != 0) || | ||||
| (BM_elem_flag_test(f, BM_ELEM_TAG) != 0) || | (BM_elem_flag_test(f, BM_ELEM_TAG) != 0) || | ||||
| (BM_elem_flag_test(f, BM_ELEM_SELECT) == 0)) { | (BM_elem_flag_test(f, BM_ELEM_SELECT) == 0)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BLI_assert(BLI_LINKSTACK_SIZE(stack) == 0); | BLI_assert(stack.is_empty()); | ||||
| do { | do { | ||||
| BM_face_select_set(bm, f, true); | BM_face_select_set(bm, f, true); | ||||
| BM_elem_flag_enable(f, BM_ELEM_TAG); | BM_elem_flag_enable(f, BM_ELEM_TAG); | ||||
| BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { | ||||
| BM_ITER_ELEM (l2, &liter2, l, BM_LOOPS_OF_LOOP) { | BM_ITER_ELEM (l2, &liter2, l, BM_LOOPS_OF_LOOP) { | ||||
| float angle_cos; | float angle_cos; | ||||
| if (BM_elem_flag_test(l2->f, BM_ELEM_TAG) || | if (BM_elem_flag_test(l2->f, BM_ELEM_TAG) || | ||||
| BM_elem_flag_test(l2->f, BM_ELEM_HIDDEN)) { | BM_elem_flag_test(l2->f, BM_ELEM_HIDDEN)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| angle_cos = dot_v3v3(f->no, l2->f->no); | angle_cos = dot_v3v3(f->no, l2->f->no); | ||||
| if (angle_cos > angle_limit_cos) { | if (angle_cos > angle_limit_cos) { | ||||
| BLI_LINKSTACK_PUSH(stack, l2->f); | stack.append(l2->f); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } while ((f = BLI_LINKSTACK_POP(stack))); | } while (!stack.is_empty() && (f = stack.pop_last())); | ||||
| } | } | ||||
| BLI_LINKSTACK_FREE(stack); | DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); | ||||
| DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); | |||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | ||||
| } | } | ||||
| MEM_freeN(objects); | MEM_freeN(objects); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void MESH_OT_faces_select_linked_flat(wmOperatorType *ot) | void MESH_OT_faces_select_linked_flat(wmOperatorType *ot) | ||||
| Show All 11 Lines | void MESH_OT_faces_select_linked_flat(wmOperatorType *ot) | ||||
| /* flags */ | /* flags */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | ||||
| /* props */ | /* props */ | ||||
| prop = RNA_def_float_rotation(ot->srna, | prop = RNA_def_float_rotation(ot->srna, | ||||
| "sharpness", | "sharpness", | ||||
| 0, | 0, | ||||
| NULL, | nullptr, | ||||
| DEG2RADF(0.01f), | DEG2RADF(0.01f), | ||||
| DEG2RADF(180.0f), | DEG2RADF(180.0f), | ||||
| "Sharpness", | "Sharpness", | ||||
| "", | "", | ||||
| DEG2RADF(1.0f), | DEG2RADF(1.0f), | ||||
| DEG2RADF(180.0f)); | DEG2RADF(180.0f)); | ||||
| RNA_def_property_float_default(prop, DEG2RADF(1.0f)); | RNA_def_property_float_default(prop, DEG2RADF(1.0f)); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | if (use_wire || use_boundary || use_multi_face || use_non_contiguous) { | ||||
| BLI_assert(!(BM_edge_is_manifold(e) && BM_edge_is_contiguous(e))); | BLI_assert(!(BM_edge_is_manifold(e) && BM_edge_is_contiguous(e))); | ||||
| BM_edge_select_set(em->bm, e, true); | BM_edge_select_set(em->bm, e, true); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); | DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | ||||
| EDBM_selectmode_flush(em); | EDBM_selectmode_flush(em); | ||||
| } | } | ||||
| MEM_freeN(objects); | MEM_freeN(objects); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| /* This gives a consistent result regardless of object order. */ | /* This gives a consistent result regardless of object order. */ | ||||
| if (ob_index) { | if (ob_index) { | ||||
| seed_iter += BLI_ghashutil_strhash_p(obedit->id.name); | seed_iter += BLI_ghashutil_strhash_p(obedit->id.name); | ||||
| } | } | ||||
| if (em->selectmode & SCE_SELECT_VERTEX) { | if (em->selectmode & SCE_SELECT_VERTEX) { | ||||
| int elem_map_len = 0; | int elem_map_len = 0; | ||||
| BMVert **elem_map = MEM_mallocN(sizeof(*elem_map) * em->bm->totvert, __func__); | BMVert **elem_map = static_cast<BMVert **>( | ||||
| MEM_mallocN(sizeof(*elem_map) * em->bm->totvert, __func__)); | |||||
| BMVert *eve; | BMVert *eve; | ||||
| BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { | BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { | ||||
| if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { | if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { | ||||
| elem_map[elem_map_len++] = eve; | elem_map[elem_map_len++] = eve; | ||||
| } | } | ||||
| } | } | ||||
| BLI_array_randomize(elem_map, sizeof(*elem_map), elem_map_len, seed_iter); | BLI_array_randomize(elem_map, sizeof(*elem_map), elem_map_len, seed_iter); | ||||
| const int count_select = elem_map_len * randfac; | const int count_select = elem_map_len * randfac; | ||||
| for (int i = 0; i < count_select; i++) { | for (int i = 0; i < count_select; i++) { | ||||
| BM_vert_select_set(em->bm, elem_map[i], select); | BM_vert_select_set(em->bm, elem_map[i], select); | ||||
| } | } | ||||
| MEM_freeN(elem_map); | MEM_freeN(elem_map); | ||||
| } | } | ||||
| else if (em->selectmode & SCE_SELECT_EDGE) { | else if (em->selectmode & SCE_SELECT_EDGE) { | ||||
| int elem_map_len = 0; | int elem_map_len = 0; | ||||
| BMEdge **elem_map = MEM_mallocN(sizeof(*elem_map) * em->bm->totedge, __func__); | BMEdge **elem_map = static_cast<BMEdge **>( | ||||
| MEM_mallocN(sizeof(*elem_map) * em->bm->totedge, __func__)); | |||||
| BMEdge *eed; | BMEdge *eed; | ||||
| BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { | BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { | ||||
| if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { | if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { | ||||
| elem_map[elem_map_len++] = eed; | elem_map[elem_map_len++] = eed; | ||||
| } | } | ||||
| } | } | ||||
| BLI_array_randomize(elem_map, sizeof(*elem_map), elem_map_len, seed_iter); | BLI_array_randomize(elem_map, sizeof(*elem_map), elem_map_len, seed_iter); | ||||
| const int count_select = elem_map_len * randfac; | const int count_select = elem_map_len * randfac; | ||||
| for (int i = 0; i < count_select; i++) { | for (int i = 0; i < count_select; i++) { | ||||
| BM_edge_select_set(em->bm, elem_map[i], select); | BM_edge_select_set(em->bm, elem_map[i], select); | ||||
| } | } | ||||
| MEM_freeN(elem_map); | MEM_freeN(elem_map); | ||||
| } | } | ||||
| else { | else { | ||||
| int elem_map_len = 0; | int elem_map_len = 0; | ||||
| BMFace **elem_map = MEM_mallocN(sizeof(*elem_map) * em->bm->totface, __func__); | BMFace **elem_map = static_cast<BMFace **>( | ||||
| MEM_mallocN(sizeof(*elem_map) * em->bm->totface, __func__)); | |||||
| 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 (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { | if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { | ||||
| elem_map[elem_map_len++] = efa; | elem_map[elem_map_len++] = efa; | ||||
| } | } | ||||
| } | } | ||||
| BLI_array_randomize(elem_map, sizeof(*elem_map), elem_map_len, seed_iter); | BLI_array_randomize(elem_map, sizeof(*elem_map), elem_map_len, seed_iter); | ||||
| const int count_select = elem_map_len * randfac; | const int count_select = elem_map_len * randfac; | ||||
| for (int i = 0; i < count_select; i++) { | for (int i = 0; i < count_select; i++) { | ||||
| BM_face_select_set(em->bm, elem_map[i], select); | BM_face_select_set(em->bm, elem_map[i], select); | ||||
| } | } | ||||
| MEM_freeN(elem_map); | MEM_freeN(elem_map); | ||||
| } | } | ||||
| if (select) { | if (select) { | ||||
| /* was EDBM_select_flush, but it over select in edge/face mode */ | /* was EDBM_select_flush, but it over select in edge/face mode */ | ||||
| EDBM_selectmode_flush(em); | EDBM_selectmode_flush(em); | ||||
| } | } | ||||
| else { | else { | ||||
| EDBM_deselect_flush(em); | EDBM_deselect_flush(em); | ||||
| } | } | ||||
| DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); | DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | ||||
| } | } | ||||
| MEM_freeN(objects); | MEM_freeN(objects); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void MESH_OT_select_random(wmOperatorType *ot) | void MESH_OT_select_random(wmOperatorType *ot) | ||||
| ▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | if (!extend) { | ||||
| if (em->bm->totvertsel) { | if (em->bm->totvertsel) { | ||||
| EDBM_flag_disable_all(em, BM_ELEM_SELECT); | EDBM_flag_disable_all(em, BM_ELEM_SELECT); | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { | BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { | ||||
| if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { | if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { | ||||
| MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); | MDeformVert *dv = static_cast<MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset)); | ||||
| /* no dv or dv set with no weight */ | /* no dv or dv set with no weight */ | ||||
| if (ELEM(NULL, dv, dv->dw)) { | if (ELEM(nullptr, dv, dv->dw)) { | ||||
| BM_vert_select_set(em->bm, eve, true); | BM_vert_select_set(em->bm, eve, true); | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (changed) { | if (changed) { | ||||
| EDBM_selectmode_flush(em); | EDBM_selectmode_flush(em); | ||||
| DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); | DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | ||||
| } | } | ||||
| } | } | ||||
| MEM_freeN(objects); | MEM_freeN(objects); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void MESH_OT_select_ungrouped(wmOperatorType *ot) | void MESH_OT_select_ungrouped(wmOperatorType *ot) | ||||
| Show All 31 Lines | static int edbm_select_axis_exec(bContext *C, wmOperator *op) | ||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| Object *obedit = CTX_data_edit_object(C); | Object *obedit = CTX_data_edit_object(C); | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| BMVert *v_act = BM_mesh_active_vert_get(em->bm); | BMVert *v_act = BM_mesh_active_vert_get(em->bm); | ||||
| const int orientation = RNA_enum_get(op->ptr, "orientation"); | const int orientation = RNA_enum_get(op->ptr, "orientation"); | ||||
| const int axis = RNA_enum_get(op->ptr, "axis"); | const int axis = RNA_enum_get(op->ptr, "axis"); | ||||
| const int sign = RNA_enum_get(op->ptr, "sign"); | const int sign = RNA_enum_get(op->ptr, "sign"); | ||||
| if (v_act == NULL) { | if (v_act == nullptr) { | ||||
| BKE_report( | BKE_report( | ||||
| op->reports, RPT_WARNING, "This operator requires an active vertex (last selected)"); | op->reports, RPT_WARNING, "This operator requires an active vertex (last selected)"); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| const float limit = RNA_float_get(op->ptr, "threshold"); | const float limit = RNA_float_get(op->ptr, "threshold"); | ||||
| float value; | float value; | ||||
| float axis_mat[3][3]; | float axis_mat[3][3]; | ||||
| /* 3D view variables may be NULL, (no need to check in poll function). */ | /* 3D view variables may be nullptr, (no need to check in poll function). */ | ||||
| ED_transform_calc_orientation_from_type_ex(scene, | ED_transform_calc_orientation_from_type_ex(scene, | ||||
| view_layer, | view_layer, | ||||
| CTX_wm_view3d(C), | CTX_wm_view3d(C), | ||||
| CTX_wm_region_view3d(C), | CTX_wm_region_view3d(C), | ||||
| obedit, | obedit, | ||||
| obedit, | obedit, | ||||
| orientation, | orientation, | ||||
| V3D_AROUND_ACTIVE, | V3D_AROUND_ACTIVE, | ||||
| ▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (changed) { | if (changed) { | ||||
| EDBM_selectmode_flush(em_iter); | EDBM_selectmode_flush(em_iter); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit_iter->data); | WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit_iter->data); | ||||
| DEG_id_tag_update(obedit_iter->data, ID_RECALC_SELECT); | DEG_id_tag_update(static_cast<ID *>(obedit_iter->data), ID_RECALC_SELECT); | ||||
| } | } | ||||
| } | } | ||||
| MEM_freeN(objects); | MEM_freeN(objects); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void MESH_OT_select_axis(wmOperatorType *ot) | void MESH_OT_select_axis(wmOperatorType *ot) | ||||
| { | { | ||||
| static const EnumPropertyItem axis_sign_items[] = { | static const EnumPropertyItem axis_sign_items[] = { | ||||
| {SELECT_AXIS_POS, "POS", 0, "Positive Axis", ""}, | {SELECT_AXIS_POS, "POS", 0, "Positive Axis", ""}, | ||||
| {SELECT_AXIS_NEG, "NEG", 0, "Negative Axis", ""}, | {SELECT_AXIS_NEG, "NEG", 0, "Negative Axis", ""}, | ||||
| {SELECT_AXIS_ALIGN, "ALIGN", 0, "Aligned Axis", ""}, | {SELECT_AXIS_ALIGN, "ALIGN", 0, "Aligned Axis", ""}, | ||||
| {0, NULL, 0, NULL, NULL}, | {0, nullptr, 0, nullptr, nullptr}, | ||||
| }; | }; | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Select Axis"; | ot->name = "Select Axis"; | ||||
| ot->description = "Select all data in the mesh on a single axis"; | ot->description = "Select all data in the mesh on a single axis"; | ||||
| ot->idname = "MESH_OT_select_axis"; | ot->idname = "MESH_OT_select_axis"; | ||||
| /* api callbacks */ | /* api callbacks */ | ||||
| ▲ Show 20 Lines • Show All 107 Lines • ▼ Show 20 Lines | |||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Select Loop to Region Operator | /** \name Select Loop to Region Operator | ||||
| * \{ */ | * \{ */ | ||||
| static int loop_find_region(BMLoop *l, int flag, GSet *visit_face_set, BMFace ***region_out) | static int loop_find_region(BMLoop *l, int flag, GSet *visit_face_set, BMFace ***region_out) | ||||
| { | { | ||||
| BMFace **region = NULL; | blender::Vector<BMFace *> stack; | ||||
| BMFace **stack = NULL; | blender::Vector<BMFace *> region; | ||||
| BLI_array_declare(region); | |||||
| BLI_array_declare(stack); | |||||
| BMFace *f; | |||||
| BLI_array_append(stack, l->f); | stack.append(l->f); | ||||
| BLI_gset_insert(visit_face_set, l->f); | BLI_gset_insert(visit_face_set, l->f); | ||||
| while (BLI_array_len(stack) > 0) { | while (!stack.is_empty()) { | ||||
| BMIter liter1, liter2; | BMIter liter1, liter2; | ||||
| BMLoop *l1, *l2; | BMLoop *l1, *l2; | ||||
| f = BLI_array_pop(stack); | BMFace *f = stack.pop_last(); | ||||
| BLI_array_append(region, f); | region.append(f); | ||||
| BM_ITER_ELEM (l1, &liter1, f, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l1, &liter1, f, BM_LOOPS_OF_FACE) { | ||||
| if (BM_elem_flag_test(l1->e, flag)) { | if (BM_elem_flag_test(l1->e, flag)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM (l2, &liter2, l1->e, BM_LOOPS_OF_EDGE) { | BM_ITER_ELEM (l2, &liter2, l1->e, BM_LOOPS_OF_EDGE) { | ||||
| /* avoids finding same region twice | /* avoids finding same region twice | ||||
| * (otherwise) the logic works fine without */ | * (otherwise) the logic works fine without */ | ||||
| if (BM_elem_flag_test(l2->f, BM_ELEM_TAG)) { | if (BM_elem_flag_test(l2->f, BM_ELEM_TAG)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (BLI_gset_add(visit_face_set, l2->f)) { | if (BLI_gset_add(visit_face_set, l2->f)) { | ||||
| BLI_array_append(stack, l2->f); | stack.append(l2->f); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| BLI_array_free(stack); | BMFace **region_alloc = static_cast<BMFace **>( | ||||
| MEM_malloc_arrayN(region.size(), sizeof(BMFace *), __func__)); | |||||
| *region_out = region; | memcpy(region_alloc, region.data(), region.as_span().size_in_bytes()); | ||||
| return BLI_array_len(region); | *region_out = region_alloc; | ||||
| return region.size(); | |||||
| } | } | ||||
| static int verg_radial(const void *va, const void *vb) | static int verg_radial(const void *va, const void *vb) | ||||
| { | { | ||||
| const BMEdge *e_a = *((const BMEdge **)va); | const BMEdge *e_a = *((const BMEdge **)va); | ||||
| const BMEdge *e_b = *((const BMEdge **)vb); | const BMEdge *e_b = *((const BMEdge **)vb); | ||||
| const int a = BM_edge_face_count(e_a); | const int a = BM_edge_face_count(e_a); | ||||
| Show All 14 Lines | |||||
| * \note faces already tagged are ignored, to avoid finding the same regions twice: | * \note faces already tagged are ignored, to avoid finding the same regions twice: | ||||
| * important when we have regions with equal face counts, see: T40309 | * important when we have regions with equal face counts, see: T40309 | ||||
| */ | */ | ||||
| static int loop_find_regions(BMEditMesh *em, const bool selbigger) | static int loop_find_regions(BMEditMesh *em, const bool selbigger) | ||||
| { | { | ||||
| GSet *visit_face_set; | GSet *visit_face_set; | ||||
| BMIter iter; | BMIter iter; | ||||
| const int edges_len = em->bm->totedgesel; | const int edges_len = em->bm->totedgesel; | ||||
| BMEdge *e, **edges; | BMEdge *e; | ||||
| int count = 0, i; | int count = 0, i; | ||||
| visit_face_set = BLI_gset_ptr_new_ex(__func__, edges_len); | visit_face_set = BLI_gset_ptr_new_ex(__func__, edges_len); | ||||
| edges = MEM_mallocN(sizeof(*edges) * edges_len, __func__); | BMEdge **edges = static_cast<BMEdge **>(MEM_mallocN(sizeof(*edges) * edges_len, __func__)); | ||||
| i = 0; | i = 0; | ||||
| BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { | BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { | ||||
| if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { | if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { | ||||
| edges[i++] = e; | edges[i++] = e; | ||||
| BM_elem_flag_enable(e, BM_ELEM_TAG); | BM_elem_flag_enable(e, BM_ELEM_TAG); | ||||
| } | } | ||||
| else { | else { | ||||
| BM_elem_flag_disable(e, BM_ELEM_TAG); | BM_elem_flag_disable(e, BM_ELEM_TAG); | ||||
| } | } | ||||
| } | } | ||||
| /* sort edges by radial cycle length */ | /* sort edges by radial cycle length */ | ||||
| qsort(edges, edges_len, sizeof(*edges), verg_radial); | qsort(edges, edges_len, sizeof(*edges), verg_radial); | ||||
| for (i = 0; i < edges_len; i++) { | for (i = 0; i < edges_len; i++) { | ||||
| BMIter liter; | BMIter liter; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMFace **region = NULL, **region_out; | BMFace **region = nullptr, **region_out; | ||||
| int c, tot = 0; | int c, tot = 0; | ||||
| e = edges[i]; | e = edges[i]; | ||||
| if (!BM_elem_flag_test(e, BM_ELEM_TAG)) { | if (!BM_elem_flag_test(e, BM_ELEM_TAG)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| Show All 32 Lines | if (region) { | ||||
| count += tot; | count += tot; | ||||
| MEM_freeN(region); | MEM_freeN(region); | ||||
| } | } | ||||
| } | } | ||||
| MEM_freeN(edges); | MEM_freeN(edges); | ||||
| BLI_gset_free(visit_face_set, NULL); | BLI_gset_free(visit_face_set, nullptr); | ||||
| return count; | return count; | ||||
| } | } | ||||
| static int edbm_loop_to_region_exec(bContext *C, wmOperator *op) | static int edbm_loop_to_region_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| const bool select_bigger = RNA_boolean_get(op->ptr, "select_bigger"); | const bool select_bigger = RNA_boolean_get(op->ptr, "select_bigger"); | ||||
| Show All 26 Lines | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (BM_elem_flag_test(f, BM_ELEM_TAG) && !BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { | if (BM_elem_flag_test(f, BM_ELEM_TAG) && !BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { | ||||
| BM_face_select_set(em->bm, f, true); | BM_face_select_set(em->bm, f, true); | ||||
| } | } | ||||
| } | } | ||||
| EDBM_selectmode_flush(em); | EDBM_selectmode_flush(em); | ||||
| DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); | DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); | ||||
| } | } | ||||
| MEM_freeN(objects); | MEM_freeN(objects); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void MESH_OT_loop_to_region(wmOperatorType *ot) | void MESH_OT_loop_to_region(wmOperatorType *ot) | ||||
| Show All 21 Lines | |||||