Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/uvedit/uvedit_ops.c
| Show First 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | |||||
| static int UNUSED_FUNCTION(ED_operator_uvmap_mesh)(bContext *C) | static int UNUSED_FUNCTION(ED_operator_uvmap_mesh)(bContext *C) | ||||
| { | { | ||||
| Object *ob = CTX_data_active_object(C); | Object *ob = CTX_data_active_object(C); | ||||
| if (ob && ob->type == OB_MESH) { | if (ob && ob->type == OB_MESH) { | ||||
| Mesh *me = ob->data; | Mesh *me = ob->data; | ||||
| if (CustomData_get_layer(&me->ldata, CD_MLOOPUV) != NULL) { | if (CustomData_get_layer(&me->ldata, CD_PROP_FLOAT2) != NULL) { | ||||
| return 1; | return 1; | ||||
| } | } | ||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| ▲ Show 20 Lines • Show All 99 Lines • ▼ Show 20 Lines | bool ED_uvedit_minmax_multi( | ||||
| 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_edit[ob_index]; | Object *obedit = objects_edit[ob_index]; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| MLoopUV *luv; | float *luv; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { | if (uvedit_uv_select_test(scene, l, offsets)) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv); | ||||
| minmax_v2v2_v2(r_min, r_max, luv->uv); | minmax_v2v2_v2(r_min, r_max, luv); | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| bool ED_uvedit_minmax(const Scene *scene, Object *obedit, float r_min[2], float r_max[2]) | bool ED_uvedit_minmax(const Scene *scene, Object *obedit, float r_min[2], float r_max[2]) | ||||
| { | { | ||||
| return ED_uvedit_minmax_multi(scene, &obedit, 1, r_min, r_max); | return ED_uvedit_minmax_multi(scene, &obedit, 1, r_min, r_max); | ||||
| } | } | ||||
| void ED_uvedit_select_all(BMesh *bm) | void ED_uvedit_select_all(BMesh *bm) | ||||
| { | { | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| MLoopUV *luv; | const BMUVOffsets offsets = BM_uv_map_get_offsets(bm); | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); | |||||
| BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | BM_ELEM_CD_SET_BOOL(l, offsets.select_vert, true); | ||||
| luv->flag |= (MLOOPUV_VERTSEL | MLOOPUV_EDGESEL); | BM_ELEM_CD_SET_BOOL(l, offsets.select_edge, true); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static bool ED_uvedit_median_multi(const Scene *scene, | static bool ED_uvedit_median_multi(const Scene *scene, | ||||
| Object **objects_edit, | Object **objects_edit, | ||||
| uint objects_len, | uint objects_len, | ||||
| float co[2]) | float co[2]) | ||||
| { | { | ||||
| uint sel = 0; | uint sel = 0; | ||||
| zero_v2(co); | zero_v2(co); | ||||
| 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_edit[ob_index]; | Object *obedit = objects_edit[ob_index]; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| MLoopUV *luv; | float *luv; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv); | ||||
| if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { | if (uvedit_uv_select_test(scene, l, offsets)) { | ||||
| add_v2_v2(co, luv->uv); | add_v2_v2(co, luv); | ||||
| sel++; | sel++; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| mul_v2_fl(co, 1.0f / (float)sel); | mul_v2_fl(co, 1.0f / (float)sel); | ||||
| ▲ Show 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | |||||
| } eUVWeldAlign; | } eUVWeldAlign; | ||||
| static bool uvedit_uv_align_weld(Scene *scene, | static bool uvedit_uv_align_weld(Scene *scene, | ||||
| BMesh *bm, | BMesh *bm, | ||||
| const eUVWeldAlign tool, | const eUVWeldAlign tool, | ||||
| const float cent[2]) | const float cent[2]) | ||||
| { | { | ||||
| bool changed = false; | bool changed = false; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(bm); | ||||
| BMIter iter; | BMIter iter; | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BMIter liter; | BMIter liter; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { | if (!uvedit_uv_select_test(scene, l, offsets)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | float *luv = BM_ELEM_CD_GET_VOID_P(l, offsets.uv); | ||||
| if (ELEM(tool, UV_ALIGN_X, UV_WELD)) { | if (ELEM(tool, UV_ALIGN_X, UV_WELD)) { | ||||
| if (luv->uv[0] != cent[0]) { | if (luv[0] != cent[0]) { | ||||
| luv->uv[0] = cent[0]; | luv[0] = cent[0]; | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| if (ELEM(tool, UV_ALIGN_Y, UV_WELD)) { | if (ELEM(tool, UV_ALIGN_Y, UV_WELD)) { | ||||
| if (luv->uv[1] != cent[1]) { | if (luv[1] != cent[1]) { | ||||
| luv->uv[1] = cent[1]; | luv[1] = cent[1]; | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| /** Bitwise-or together, then choose #MLoopUV with highest value. */ | /** Bitwise-or together, then choose loop with highest value. */ | ||||
| typedef enum eUVEndPointPrecedence { | typedef enum eUVEndPointPrecedence { | ||||
| UVEP_INVALID = 0, | UVEP_INVALID = 0, | ||||
| UVEP_SELECTED = (1 << 0), | UVEP_SELECTED = (1 << 0), | ||||
| UVEP_PINNED = (1 << 1), /* i.e. Pinned verts are preferred to selected. */ | UVEP_PINNED = (1 << 1), /* i.e. Pinned verts are preferred to selected. */ | ||||
| } eUVEndPointPrecedence; | } eUVEndPointPrecedence; | ||||
| static eUVEndPointPrecedence uvedit_line_update_get_precedence(const MLoopUV *luv) | static eUVEndPointPrecedence uvedit_line_update_get_precedence(const bool pinned) | ||||
| { | { | ||||
| eUVEndPointPrecedence precedence = UVEP_SELECTED; | eUVEndPointPrecedence precedence = UVEP_SELECTED; | ||||
| if (luv->flag & MLOOPUV_PINNED) { | if (pinned) { | ||||
| precedence |= UVEP_PINNED; | precedence |= UVEP_PINNED; | ||||
| } | } | ||||
| return precedence; | return precedence; | ||||
| } | } | ||||
| /** | /** | ||||
| * Helper to find two endpoints (`a` and `b`) which have higher precedence, and are far apart. | * Helper to find two endpoints (`a` and `b`) which have higher precedence, and are far apart. | ||||
| * Note that is only a heuristic and won't always find the best two endpoints. | * Note that is only a heuristic and won't always find the best two endpoints. | ||||
| */ | */ | ||||
| static bool uvedit_line_update_endpoint(const MLoopUV *luv, | static bool uvedit_line_update_endpoint(const float *luv, | ||||
| const bool pinned, | |||||
| float uv_a[2], | float uv_a[2], | ||||
| eUVEndPointPrecedence *prec_a, | eUVEndPointPrecedence *prec_a, | ||||
| float uv_b[2], | float uv_b[2], | ||||
| eUVEndPointPrecedence *prec_b) | eUVEndPointPrecedence *prec_b) | ||||
| { | { | ||||
| eUVEndPointPrecedence flags = uvedit_line_update_get_precedence(luv); | eUVEndPointPrecedence flags = uvedit_line_update_get_precedence(pinned); | ||||
| float len_sq_a = len_squared_v2v2(uv_a, luv->uv); | float len_sq_a = len_squared_v2v2(uv_a, luv); | ||||
| float len_sq_b = len_squared_v2v2(uv_b, luv->uv); | float len_sq_b = len_squared_v2v2(uv_b, luv); | ||||
| /* Caching the value of `len_sq_ab` is unlikely to be faster than recalculating. | /* Caching the value of `len_sq_ab` is unlikely to be faster than recalculating. | ||||
| * Profile before optimizing. */ | * Profile before optimizing. */ | ||||
| float len_sq_ab = len_squared_v2v2(uv_a, uv_b); | float len_sq_ab = len_squared_v2v2(uv_a, uv_b); | ||||
| if ((*prec_a < flags && 0.0f < len_sq_b) || (*prec_a == flags && len_sq_ab < len_sq_b)) { | if ((*prec_a < flags && 0.0f < len_sq_b) || (*prec_a == flags && len_sq_ab < len_sq_b)) { | ||||
| *prec_a = flags; | *prec_a = flags; | ||||
| copy_v2_v2(uv_a, luv->uv); | copy_v2_v2(uv_a, luv); | ||||
| return true; | return true; | ||||
| } | } | ||||
| if ((*prec_b < flags && 0.0f < len_sq_a) || (*prec_b == flags && len_sq_ab < len_sq_a)) { | if ((*prec_b < flags && 0.0f < len_sq_a) || (*prec_b == flags && len_sq_ab < len_sq_a)) { | ||||
| *prec_b = flags; | *prec_b = flags; | ||||
| copy_v2_v2(uv_b, luv->uv); | copy_v2_v2(uv_b, luv); | ||||
| return true; | return true; | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| /** | /** | ||||
| * Find two end extreme points to specify a line, then straighten `len` elements | * Find two end extreme points to specify a line, then straighten `len` elements | ||||
| * by moving UVs on the X-axis, Y-axis, or the closest point on the line segment. | * by moving UVs on the X-axis, Y-axis, or the closest point on the line segment. | ||||
| */ | */ | ||||
| static bool uvedit_uv_straighten_elements(const UvElement *element, | static bool uvedit_uv_straighten_elements(const UvElement *element, | ||||
| const int len, | const int len, | ||||
| const int cd_loop_uv_offset, | const BMUVOffsets offsets, | ||||
| const eUVWeldAlign tool) | const eUVWeldAlign tool) | ||||
| { | { | ||||
| float uv_start[2]; | float uv_start[2]; | ||||
| float uv_end[2]; | float uv_end[2]; | ||||
| eUVEndPointPrecedence prec_start = UVEP_INVALID; | eUVEndPointPrecedence prec_start = UVEP_INVALID; | ||||
| eUVEndPointPrecedence prec_end = UVEP_INVALID; | eUVEndPointPrecedence prec_end = UVEP_INVALID; | ||||
| /* Find start and end of line. */ | /* Find start and end of line. */ | ||||
| for (int i = 0; i < 10; i++) { /* Heuristic to prevent infinite loop. */ | for (int i = 0; i < 10; i++) { /* Heuristic to prevent infinite loop. */ | ||||
| bool update = false; | bool update = false; | ||||
| for (int j = 0; j < len; j++) { | for (int j = 0; j < len; j++) { | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(element[j].l, cd_loop_uv_offset); | float *luv = BM_ELEM_CD_GET_FLOAT_P(element[j].l, offsets.uv); | ||||
| update |= uvedit_line_update_endpoint(luv, uv_start, &prec_start, uv_end, &prec_end); | bool pinned = BM_ELEM_CD_GET_BOOL(element[j].l, offsets.pin); | ||||
| update |= uvedit_line_update_endpoint(luv, pinned, uv_start, &prec_start, uv_end, &prec_end); | |||||
| } | } | ||||
| if (!update) { | if (!update) { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| if (prec_start == UVEP_INVALID || prec_end == UVEP_INVALID) { | if (prec_start == UVEP_INVALID || prec_end == UVEP_INVALID) { | ||||
| return false; /* Unable to find two endpoints. */ | return false; /* Unable to find two endpoints. */ | ||||
| Show All 18 Lines | else if (tool_local == UV_STRAIGHTEN_Y) { | ||||
| } | } | ||||
| else { | else { | ||||
| a = (uv_end[1] - uv_start[1]) / (uv_end[0] - uv_start[0]); | a = (uv_end[1] - uv_start[1]) / (uv_end[0] - uv_start[0]); | ||||
| } | } | ||||
| } | } | ||||
| bool changed = false; | bool changed = false; | ||||
| for (int j = 0; j < len; j++) { | for (int j = 0; j < len; j++) { | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(element[j].l, cd_loop_uv_offset); | float *luv = BM_ELEM_CD_GET_FLOAT_P(element[j].l, offsets.uv); | ||||
| /* Projection of point (x, y) over line (x1, y1, x2, y2) along X axis: | /* Projection of point (x, y) over line (x1, y1, x2, y2) along X axis: | ||||
| * new_y = (y2 - y1) / (x2 - x1) * (x - x1) + y1 | * new_y = (y2 - y1) / (x2 - x1) * (x - x1) + y1 | ||||
| * Maybe this should be a BLI func? Or is it already existing? | * Maybe this should be a BLI func? Or is it already existing? | ||||
| * Could use interp_v2_v2v2, but not sure it's worth it here. */ | * Could use interp_v2_v2v2, but not sure it's worth it here. */ | ||||
| if (tool_local == UV_STRAIGHTEN_X) { | if (tool_local == UV_STRAIGHTEN_X) { | ||||
| luv->uv[0] = a * (luv->uv[1] - uv_start[1]) + uv_start[0]; | luv[0] = a * (luv[1] - uv_start[1]) + uv_start[0]; | ||||
| } | } | ||||
| else if (tool_local == UV_STRAIGHTEN_Y) { | else if (tool_local == UV_STRAIGHTEN_Y) { | ||||
| luv->uv[1] = a * (luv->uv[0] - uv_start[0]) + uv_start[1]; | luv[1] = a * (luv[0] - uv_start[0]) + uv_start[1]; | ||||
| } | } | ||||
| else { | else { | ||||
| closest_to_line_segment_v2(luv->uv, luv->uv, uv_start, uv_end); | closest_to_line_segment_v2(luv, luv, uv_start, uv_end); | ||||
| } | } | ||||
| changed = true; /* TODO: Did the UV actually move? */ | changed = true; /* TODO: Did the UV actually move? */ | ||||
| } | } | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| /** | /** | ||||
| * Group selected UVs into islands, then apply uvedit_uv_straighten_elements to each island. | * Group selected UVs into islands, then apply uvedit_uv_straighten_elements to each island. | ||||
| */ | */ | ||||
| static bool uvedit_uv_straighten(Scene *scene, BMesh *bm, eUVWeldAlign tool) | static bool uvedit_uv_straighten(Scene *scene, BMesh *bm, eUVWeldAlign tool) | ||||
| { | { | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(bm); | ||||
| if (cd_loop_uv_offset == -1) { | if (offsets.uv == -1) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| UvElementMap *element_map = BM_uv_element_map_create(bm, scene, true, false, true, true); | UvElementMap *element_map = BM_uv_element_map_create(bm, scene, true, false, true, true); | ||||
| if (element_map == NULL) { | if (element_map == NULL) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| bool changed = false; | bool changed = false; | ||||
| for (int i = 0; i < element_map->total_islands; i++) { | for (int i = 0; i < element_map->total_islands; i++) { | ||||
| changed |= uvedit_uv_straighten_elements(element_map->storage + element_map->island_indices[i], | changed |= uvedit_uv_straighten_elements(element_map->storage + element_map->island_indices[i], | ||||
| element_map->island_total_uvs[i], | element_map->island_total_uvs[i], | ||||
| cd_loop_uv_offset, | offsets, | ||||
| tool); | tool); | ||||
| } | } | ||||
| BM_uv_element_map_free(element_map); | BM_uv_element_map_free(element_map); | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| static void uv_weld_align(bContext *C, eUVWeldAlign tool) | static void uv_weld_align(bContext *C, eUVWeldAlign tool) | ||||
| Show All 15 Lines | if (tool == UV_ALIGN_AUTO) { | ||||
| 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 (synced_selection && (em->bm->totvertsel == 0)) { | if (synced_selection && (em->bm->totvertsel == 0)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { | if (uvedit_uv_select_test(scene, l, offsets)) { | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | float *luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv); | ||||
| minmax_v2v2_v2(min, max, luv->uv); | minmax_v2v2_v2(min, max, luv); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| tool = (max[0] - min[0] >= max[1] - min[1]) ? UV_ALIGN_Y : UV_ALIGN_X; | tool = (max[0] - min[0] >= max[1] - min[1]) ? UV_ALIGN_Y : UV_ALIGN_X; | ||||
| } | } | ||||
| ED_uvedit_center_multi(scene, objects, objects_len, cent, 0); | ED_uvedit_center_multi(scene, objects, objects_len, cent, 0); | ||||
| ▲ Show 20 Lines • Show All 92 Lines • ▼ Show 20 Lines | static int uv_remove_doubles_to_selected(bContext *C, wmOperator *op) | ||||
| const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; | const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; | ||||
| uint objects_len = 0; | uint objects_len = 0; | ||||
| Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( | Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( | ||||
| scene, view_layer, ((View3D *)NULL), &objects_len); | scene, view_layer, ((View3D *)NULL), &objects_len); | ||||
| bool *changed = MEM_callocN(sizeof(bool) * objects_len, "uv_remove_doubles_selected.changed"); | bool *changed = MEM_callocN(sizeof(bool) * objects_len, "uv_remove_doubles_selected.changed"); | ||||
| /* Maximum index of an objects[i]'s MLoopUVs in MLoopUV_arr. | /* Maximum index of an objects[i]'s UVs in UV_arr. | ||||
| * It helps find which MLoopUV in *MLoopUV_arr belongs to which object. */ | * It helps find which UV in *mloopuv_arr belongs to which object. */ | ||||
| uint *ob_mloopuv_max_idx = MEM_callocN(sizeof(uint) * objects_len, | uint *ob_mloopuv_max_idx = MEM_callocN(sizeof(uint) * objects_len, | ||||
| "uv_remove_doubles_selected.ob_mloopuv_max_idx"); | "uv_remove_doubles_selected.ob_mloopuv_max_idx"); | ||||
| /* Calculate max possible number of kdtree nodes. */ | /* Calculate max possible number of kdtree nodes. */ | ||||
| int uv_maxlen = 0; | int uv_maxlen = 0; | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| Object *obedit = objects[ob_index]; | Object *obedit = objects[ob_index]; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| if (synced_selection && (em->bm->totvertsel == 0)) { | if (synced_selection && (em->bm->totvertsel == 0)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| uv_maxlen += em->bm->totloop; | uv_maxlen += em->bm->totloop; | ||||
| } | } | ||||
| KDTree_2d *tree = BLI_kdtree_2d_new(uv_maxlen); | KDTree_2d *tree = BLI_kdtree_2d_new(uv_maxlen); | ||||
| int *duplicates = NULL; | int *duplicates = NULL; | ||||
| BLI_array_declare(duplicates); | BLI_array_declare(duplicates); | ||||
| MLoopUV **mloopuv_arr = NULL; | float **mloopuv_arr = NULL; | ||||
| BLI_array_declare(mloopuv_arr); | BLI_array_declare(mloopuv_arr); | ||||
| int mloopuv_count = 0; /* Also used for *duplicates count. */ | int mloopuv_count = 0; /* Also used for *duplicates count. */ | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| 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 (synced_selection && (em->bm->totvertsel == 0)) { | if (synced_selection && (em->bm->totvertsel == 0)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { | if (uvedit_uv_select_test(scene, l, offsets)) { | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | float *luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv); | ||||
| BLI_kdtree_2d_insert(tree, mloopuv_count, luv->uv); | BLI_kdtree_2d_insert(tree, mloopuv_count, luv); | ||||
| BLI_array_append(duplicates, -1); | BLI_array_append(duplicates, -1); | ||||
| BLI_array_append(mloopuv_arr, luv); | BLI_array_append(mloopuv_arr, luv); | ||||
| mloopuv_count++; | mloopuv_count++; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| ob_mloopuv_max_idx[ob_index] = mloopuv_count - 1; | ob_mloopuv_max_idx[ob_index] = mloopuv_count - 1; | ||||
| Show All 10 Lines | for (int i = 0; i < mloopuv_count; i++) { | ||||
| if (duplicates[i] == -1) { /* If doesn't reference another */ | if (duplicates[i] == -1) { /* If doesn't reference another */ | ||||
| uv_duplicate_count[i]++; /* self */ | uv_duplicate_count[i]++; /* self */ | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (duplicates[i] != i) { | if (duplicates[i] != i) { | ||||
| /* If not self then accumulate uv for averaging. | /* If not self then accumulate uv for averaging. | ||||
| * Self uv is already present in accumulator */ | * Self uv is already present in accumulator */ | ||||
| add_v2_v2(mloopuv_arr[duplicates[i]]->uv, mloopuv_arr[i]->uv); | add_v2_v2(mloopuv_arr[duplicates[i]], mloopuv_arr[i]); | ||||
| } | } | ||||
| uv_duplicate_count[duplicates[i]]++; | uv_duplicate_count[duplicates[i]]++; | ||||
| } | } | ||||
| for (int i = 0; i < mloopuv_count; i++) { | for (int i = 0; i < mloopuv_count; i++) { | ||||
| if (uv_duplicate_count[i] < 2) { | if (uv_duplicate_count[i] < 2) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| mul_v2_fl(mloopuv_arr[i]->uv, 1.0f / (float)uv_duplicate_count[i]); | mul_v2_fl(mloopuv_arr[i], 1.0f / (float)uv_duplicate_count[i]); | ||||
| } | } | ||||
| MEM_freeN(uv_duplicate_count); | MEM_freeN(uv_duplicate_count); | ||||
| /* Update duplicated uvs. */ | /* Update duplicated uvs. */ | ||||
| uint ob_index = 0; | uint ob_index = 0; | ||||
| for (int i = 0; i < mloopuv_count; i++) { | for (int i = 0; i < mloopuv_count; i++) { | ||||
| /* Make sure we know which object owns the MLoopUV at this index. | /* Make sure we know which object owns the mloopuv at this index. | ||||
| * Remember that in some cases the object will have no loop uv, | * Remember that in some cases the object will have no loop uv, | ||||
| * thus we need the while loop, and not simply an if check. */ | * thus we need the while loop, and not simply an if check. */ | ||||
| while (ob_mloopuv_max_idx[ob_index] < i) { | while (ob_mloopuv_max_idx[ob_index] < i) { | ||||
| ob_index++; | ob_index++; | ||||
| } | } | ||||
| if (duplicates[i] == -1) { | if (duplicates[i] == -1) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| copy_v2_v2(mloopuv_arr[i]->uv, mloopuv_arr[duplicates[i]]->uv); | copy_v2_v2(mloopuv_arr[i], mloopuv_arr[duplicates[i]]); | ||||
| changed[ob_index] = true; | changed[ob_index] = true; | ||||
| } | } | ||||
| for (ob_index = 0; ob_index < objects_len; ob_index++) { | for (ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| if (changed[ob_index]) { | if (changed[ob_index]) { | ||||
| Object *obedit = objects[ob_index]; | Object *obedit = objects[ob_index]; | ||||
| uvedit_live_unwrap_update(sima, scene, obedit); | uvedit_live_unwrap_update(sima, scene, obedit); | ||||
| DEG_id_tag_update(obedit->data, 0); | DEG_id_tag_update(obedit->data, 0); | ||||
| Show All 31 Lines | static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op) | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| Object *obedit = objects[ob_index]; | Object *obedit = objects[ob_index]; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| uv_maxlen += em->bm->totloop; | uv_maxlen += em->bm->totloop; | ||||
| } | } | ||||
| KDTree_2d *tree = BLI_kdtree_2d_new(uv_maxlen); | KDTree_2d *tree = BLI_kdtree_2d_new(uv_maxlen); | ||||
| MLoopUV **mloopuv_arr = NULL; | float **mloopuv_arr = NULL; | ||||
| BLI_array_declare(mloopuv_arr); | BLI_array_declare(mloopuv_arr); | ||||
| int mloopuv_count = 0; | int mloopuv_count = 0; | ||||
| /* Add visible non-selected uvs to tree */ | /* Add visible non-selected uvs to tree */ | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| 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 (synced_selection && (em->bm->totvertsel == em->bm->totvert)) { | if (synced_selection && (em->bm->totvertsel == em->bm->totvert)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { | if (!uvedit_uv_select_test(scene, l, offsets)) { | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | float *luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv); | ||||
| BLI_kdtree_2d_insert(tree, mloopuv_count, luv->uv); | BLI_kdtree_2d_insert(tree, mloopuv_count, luv); | ||||
| BLI_array_append(mloopuv_arr, luv); | BLI_array_append(mloopuv_arr, luv); | ||||
| mloopuv_count++; | mloopuv_count++; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| BLI_kdtree_2d_balance(tree); | BLI_kdtree_2d_balance(tree); | ||||
| /* For each selected uv, find duplicate non selected uv. */ | /* For each selected uv, find duplicate non selected uv. */ | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| bool changed = false; | bool changed = false; | ||||
| 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 (synced_selection && (em->bm->totvertsel == 0)) { | if (synced_selection && (em->bm->totvertsel == 0)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { | if (uvedit_uv_select_test(scene, l, offsets)) { | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | float *luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv); | ||||
| KDTreeNearest_2d nearest; | KDTreeNearest_2d nearest; | ||||
| const int i = BLI_kdtree_2d_find_nearest(tree, luv->uv, &nearest); | const int i = BLI_kdtree_2d_find_nearest(tree, luv, &nearest); | ||||
| if (i != -1 && nearest.dist < threshold) { | if (i != -1 && nearest.dist < threshold) { | ||||
| copy_v2_v2(luv->uv, mloopuv_arr[i]->uv); | copy_v2_v2(luv, mloopuv_arr[i]); | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (changed) { | if (changed) { | ||||
| uvedit_live_unwrap_update(sima, scene, obedit); | uvedit_live_unwrap_update(sima, scene, obedit); | ||||
| ▲ Show 20 Lines • Show All 171 Lines • ▼ Show 20 Lines | |||||
| * \{ */ | * \{ */ | ||||
| static bool uv_snap_uvs_to_cursor(Scene *scene, Object *obedit, const float cursor[2]) | static bool uv_snap_uvs_to_cursor(Scene *scene, Object *obedit, const float cursor[2]) | ||||
| { | { | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| MLoopUV *luv; | float *luv; | ||||
| bool changed = false; | bool changed = false; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { | if (uvedit_uv_select_test(scene, l, offsets)) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv); | ||||
| copy_v2_v2(luv->uv, cursor); | copy_v2_v2(luv, cursor); | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| static bool uv_snap_uvs_offset(Scene *scene, Object *obedit, const float offset[2]) | static bool uv_snap_uvs_offset(Scene *scene, Object *obedit, const float offset[2]) | ||||
| { | { | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| MLoopUV *luv; | float *luv; | ||||
| bool changed = false; | bool changed = false; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { | if (uvedit_uv_select_test(scene, l, offsets)) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv); | ||||
| add_v2_v2(luv->uv, offset); | add_v2_v2(luv, offset); | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Object *obedit) | static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Object *obedit) | ||||
| { | { | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| BMesh *bm = em->bm; | BMesh *bm = em->bm; | ||||
| BMFace *f; | BMFace *f; | ||||
| BMLoop *l, *lsub; | BMLoop *l, *lsub; | ||||
| BMIter iter, liter, lsubiter; | BMIter iter, liter, lsubiter; | ||||
| MLoopUV *luv; | float *luv; | ||||
| bool changed = false; | bool changed = false; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | ||||
| /* index every vert that has a selected UV using it, but only once so as to | /* index every vert that has a selected UV using it, but only once so as to | ||||
| * get unique indices and to count how much to malloc */ | * get unique indices and to count how much to malloc */ | ||||
| BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { | ||||
| if (uvedit_face_visible_test(scene, f)) { | if (uvedit_face_visible_test(scene, f)) { | ||||
| 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_elem_flag_set(l, BM_ELEM_TAG, uvedit_uv_select_test(scene, l, cd_loop_uv_offset)); | BM_elem_flag_set(l, BM_ELEM_TAG, uvedit_uv_select_test(scene, l, offsets)); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| BM_elem_flag_disable(f, BM_ELEM_TAG); | BM_elem_flag_disable(f, BM_ELEM_TAG); | ||||
| } | } | ||||
| } | } | ||||
| 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_TAG)) { /* Face: visible. */ | if (BM_elem_flag_test(f, BM_ELEM_TAG)) { /* Face: visible. */ | ||||
| BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { | ||||
| if (BM_elem_flag_test(l, BM_ELEM_TAG)) { /* Loop: selected. */ | if (BM_elem_flag_test(l, BM_ELEM_TAG)) { /* Loop: selected. */ | ||||
| float uv[2] = {0.0f, 0.0f}; | float uv[2] = {0.0f, 0.0f}; | ||||
| int uv_tot = 0; | int uv_tot = 0; | ||||
| BM_ITER_ELEM (lsub, &lsubiter, l->v, BM_LOOPS_OF_VERT) { | BM_ITER_ELEM (lsub, &lsubiter, l->v, BM_LOOPS_OF_VERT) { | ||||
| if (BM_elem_flag_test(lsub->f, BM_ELEM_TAG) && /* Face: visible. */ | if (BM_elem_flag_test(lsub->f, BM_ELEM_TAG) && /* Face: visible. */ | ||||
| !BM_elem_flag_test(lsub, BM_ELEM_TAG)) /* Loop: unselected. */ | !BM_elem_flag_test(lsub, BM_ELEM_TAG)) /* Loop: unselected. */ | ||||
| { | { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(lsub, cd_loop_uv_offset); | luv = BM_ELEM_CD_GET_FLOAT_P(lsub, offsets.uv); | ||||
| add_v2_v2(uv, luv->uv); | add_v2_v2(uv, luv); | ||||
| uv_tot++; | uv_tot++; | ||||
| } | } | ||||
| } | } | ||||
| if (uv_tot) { | if (uv_tot) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv); | ||||
| mul_v2_v2fl(luv->uv, uv, 1.0f / (float)uv_tot); | mul_v2_v2fl(luv, uv, 1.0f / (float)uv_tot); | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| static bool uv_snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit) | static bool uv_snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit) | ||||
| { | { | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| MLoopUV *luv; | float *luv; | ||||
| int width = 0, height = 0; | int width = 0, height = 0; | ||||
| float w, h; | float w, h; | ||||
| bool changed = false; | bool changed = false; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | ||||
| ED_space_image_get_size(sima, &width, &height); | ED_space_image_get_size(sima, &width, &height); | ||||
| w = (float)width; | w = (float)width; | ||||
| h = (float)height; | h = (float)height; | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { | if (uvedit_uv_select_test(scene, l, offsets)) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv); | ||||
| uv_snap_to_pixel(luv->uv, w, h); | uv_snap_to_pixel(luv, w, h); | ||||
| } | } | ||||
| } | } | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | |||||
| static int uv_pin_exec(bContext *C, wmOperator *op) | static int uv_pin_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| Scene *scene = CTX_data_scene(C); | Scene *scene = CTX_data_scene(C); | ||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| MLoopUV *luv; | |||||
| const ToolSettings *ts = scene->toolsettings; | const ToolSettings *ts = scene->toolsettings; | ||||
| const bool clear = RNA_boolean_get(op->ptr, "clear"); | const bool clear = RNA_boolean_get(op->ptr, "clear"); | ||||
| const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; | const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; | ||||
| uint objects_len = 0; | uint objects_len = 0; | ||||
| Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( | Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( | ||||
| scene, view_layer, ((View3D *)NULL), &objects_len); | scene, view_layer, ((View3D *)NULL), &objects_len); | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| Object *obedit = objects[ob_index]; | Object *obedit = objects[ob_index]; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | BMEditMesh *em = BKE_editmesh_from_object(obedit); | ||||
| bool changed = false; | bool changed = false; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const char *active_uv_name = CustomData_get_active_layer_name(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| BM_uv_map_ensure_pin_attr(em->bm, active_uv_name); | |||||
| const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | |||||
| if (synced_selection && (em->bm->totvertsel == 0)) { | if (synced_selection && (em->bm->totvertsel == 0)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | |||||
| if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { | if (uvedit_uv_select_test(scene, l, offsets)) { | ||||
| changed = true; | changed = true; | ||||
| if (clear) { | BM_ELEM_CD_SET_BOOL(l, offsets.pin, !clear); | ||||
| luv->flag &= ~MLOOPUV_PINNED; | |||||
| } | |||||
| else { | |||||
| luv->flag |= MLOOPUV_PINNED; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (changed) { | if (changed) { | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); | ||||
| DEG_id_tag_update(obedit->data, ID_RECALC_COPY_ON_WRITE); | DEG_id_tag_update(obedit->data, ID_RECALC_COPY_ON_WRITE); | ||||
| } | } | ||||
| Show All 22 Lines | |||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Hide Operator | /** \name Hide Operator | ||||
| * \{ */ | * \{ */ | ||||
| /* Check if vertex/edge is selected or unselected based on #bool_test arg. Needed for select swap | /* check if we are selected or unselected based on 'bool_test' arg, | ||||
| * support */ | * needed for select swap support */ | ||||
| #define UV_VERT_SEL_TEST(luv, bool_test) \ | #define UV_VERT_SEL_TEST(l, bool_test) (BM_ELEM_CD_GET_BOOL(l, offsets.select_vert) == bool_test) | ||||
| ((((luv)->flag & MLOOPUV_VERTSEL) == MLOOPUV_VERTSEL) == bool_test) | |||||
| #define UV_EDGE_SEL_TEST(luv, bool_test) \ | #define UV_EDGE_SEL_TEST(l, bool_test) (BM_ELEM_CD_GET_BOOL(l, offsets.select_edge) == bool_test) | ||||
| ((((luv)->flag & MLOOPUV_EDGESEL) == MLOOPUV_EDGESEL) == bool_test) | |||||
| /* Is the specified UV face, selected or unselected depending on bool_test. */ | /* is every UV vert selected or unselected depending on bool_test */ | ||||
| static bool bm_face_is_all_uv_sel(BMFace *f, bool select_test, const int cd_loop_uv_offset) | static bool bm_face_is_all_uv_sel(BMFace *f, bool select_test, const BMUVOffsets offsets) | ||||
| { | { | ||||
| BMLoop *l_iter; | BMLoop *l_iter; | ||||
| BMLoop *l_first; | BMLoop *l_first; | ||||
| l_iter = l_first = BM_FACE_FIRST_LOOP(f); | l_iter = l_first = BM_FACE_FIRST_LOOP(f); | ||||
| do { | do { | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset); | if (!UV_EDGE_SEL_TEST(l_iter, select_test)) { | ||||
| if (!UV_EDGE_SEL_TEST(luv, select_test)) { | |||||
| return false; | return false; | ||||
| } | } | ||||
| } while ((l_iter = l_iter->next) != l_first); | } while ((l_iter = l_iter->next) != l_first); | ||||
| return true; | return true; | ||||
| } | } | ||||
| static int uv_hide_exec(bContext *C, wmOperator *op) | static int uv_hide_exec(bContext *C, wmOperator *op) | ||||
| Show All 9 Lines | Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( | ||||
| scene, view_layer, ((View3D *)NULL), &objects_len); | scene, view_layer, ((View3D *)NULL), &objects_len); | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| Object *ob = objects[ob_index]; | Object *ob = objects[ob_index]; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(ob); | BMEditMesh *em = BKE_editmesh_from_object(ob); | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| MLoopUV *luv; | |||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const char *active_uv_name = CustomData_get_active_layer_name(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| BM_uv_map_ensure_vert_select_attr(em->bm, active_uv_name); | |||||
| BM_uv_map_ensure_edge_select_attr(em->bm, active_uv_name); | |||||
| const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | |||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | if (ts->uv_flag & UV_SYNC_SELECTION) { | ||||
| if (EDBM_mesh_hide(em, swap)) { | if (EDBM_mesh_hide(em, swap)) { | ||||
| EDBM_update(ob->data, | EDBM_update(ob->data, | ||||
| &(const struct EDBMUpdate_Params){ | &(const struct EDBMUpdate_Params){ | ||||
| .calc_looptri = true, | .calc_looptri = true, | ||||
| .calc_normals = false, | .calc_normals = false, | ||||
| .is_destructive = false, | .is_destructive = false, | ||||
| }); | }); | ||||
| } | } | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| int hide = 0; | int hide = 0; | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | |||||
| if (UV_VERT_SEL_TEST(luv, !swap) || UV_EDGE_SEL_TEST(luv, !swap)) { | if (UV_VERT_SEL_TEST(l, !swap) || UV_EDGE_SEL_TEST(l, !swap)) { | ||||
| hide = 1; | hide = 1; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| if (hide) { | if (hide) { | ||||
| if (use_face_center) { | if (use_face_center) { | ||||
| if (em->selectmode == SCE_SELECT_FACE) { | if (em->selectmode == SCE_SELECT_FACE) { | ||||
| /* Deselect BMesh face if UV face is (de)selected depending on #swap. */ | /* Deselect BMesh face if UV face is (de)selected depending on #swap. */ | ||||
| if (bm_face_is_all_uv_sel(efa, !swap, cd_loop_uv_offset)) { | if (bm_face_is_all_uv_sel(efa, !swap, offsets)) { | ||||
| BM_face_select_set(em->bm, efa, false); | BM_face_select_set(em->bm, efa, false); | ||||
| } | } | ||||
| uvedit_face_select_disable(scene, em->bm, efa, cd_loop_uv_offset); | uvedit_face_select_disable(scene, em->bm, efa, offsets); | ||||
| } | } | ||||
| else { | else { | ||||
| if (bm_face_is_all_uv_sel(efa, true, cd_loop_uv_offset) == !swap) { | if (bm_face_is_all_uv_sel(efa, true, offsets) == !swap) { | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | |||||
| /* For both cases rely on edge sel tests, since all vert sel tests are invalid in | /* For both cases rely on edge sel tests, since all vert sel tests are invalid in | ||||
| * case of sticky selections. */ | * case of sticky selections. */ | ||||
| if (UV_EDGE_SEL_TEST(luv, !swap) && (em->selectmode == SCE_SELECT_EDGE)) { | if (UV_EDGE_SEL_TEST(l, !swap) && (em->selectmode == SCE_SELECT_EDGE)) { | ||||
| BM_edge_select_set(em->bm, l->e, false); | BM_edge_select_set(em->bm, l->e, false); | ||||
| } | } | ||||
| else if (UV_EDGE_SEL_TEST(luv, !swap) && (em->selectmode == SCE_SELECT_VERTEX)) { | else if (UV_EDGE_SEL_TEST(l, !swap) && (em->selectmode == SCE_SELECT_VERTEX)) { | ||||
| BM_vert_select_set(em->bm, l->v, false); | BM_vert_select_set(em->bm, l->v, false); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (!swap) { | if (!swap) { | ||||
| uvedit_face_select_disable(scene, em->bm, efa, cd_loop_uv_offset); | uvedit_face_select_disable(scene, em->bm, efa, offsets); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else if (em->selectmode == SCE_SELECT_FACE) { | else if (em->selectmode == SCE_SELECT_FACE) { | ||||
| /* Deselect BMesh face depending on the type of UV selectmode and the type of UV element | /* Deselect BMesh face depending on the type of UV selectmode and the type of UV element | ||||
| * being considered. */ | * being considered. */ | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | if (UV_EDGE_SEL_TEST(l, !swap) && (ts->uv_selectmode == UV_SELECT_EDGE)) { | ||||
| if (UV_EDGE_SEL_TEST(luv, !swap) && (ts->uv_selectmode == UV_SELECT_EDGE)) { | |||||
| BM_face_select_set(em->bm, efa, false); | BM_face_select_set(em->bm, efa, false); | ||||
| break; | break; | ||||
| } | } | ||||
| if (UV_VERT_SEL_TEST(luv, !swap) && (ts->uv_selectmode == UV_SELECT_VERTEX)) { | if (UV_VERT_SEL_TEST(l, !swap) && (ts->uv_selectmode == UV_SELECT_VERTEX)) { | ||||
| BM_face_select_set(em->bm, efa, false); | BM_face_select_set(em->bm, efa, false); | ||||
| break; | break; | ||||
| } | } | ||||
| if (ts->uv_selectmode == UV_SELECT_ISLAND) { | if (ts->uv_selectmode == UV_SELECT_ISLAND) { | ||||
| BM_face_select_set(em->bm, efa, false); | BM_face_select_set(em->bm, efa, false); | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| uvedit_face_select_disable(scene, em->bm, efa, cd_loop_uv_offset); | uvedit_face_select_disable(scene, em->bm, efa, offsets); | ||||
| } | } | ||||
| else { | else { | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | if (UV_EDGE_SEL_TEST(l, !swap) && (ts->uv_selectmode == UV_SELECT_EDGE)) { | ||||
| if (UV_EDGE_SEL_TEST(luv, !swap) && (ts->uv_selectmode == UV_SELECT_EDGE)) { | |||||
| if (em->selectmode == SCE_SELECT_EDGE) { | if (em->selectmode == SCE_SELECT_EDGE) { | ||||
| BM_edge_select_set(em->bm, l->e, false); | BM_edge_select_set(em->bm, l->e, false); | ||||
| } | } | ||||
| else { | else { | ||||
| BM_vert_select_set(em->bm, l->v, false); | BM_vert_select_set(em->bm, l->v, false); | ||||
| BM_vert_select_set(em->bm, l->next->v, false); | BM_vert_select_set(em->bm, l->next->v, false); | ||||
| } | } | ||||
| } | } | ||||
| else if (UV_VERT_SEL_TEST(luv, !swap) && (ts->uv_selectmode != UV_SELECT_EDGE)) { | else if (UV_VERT_SEL_TEST(l, !swap) && (ts->uv_selectmode != UV_SELECT_EDGE)) { | ||||
| if (em->selectmode == SCE_SELECT_EDGE) { | if (em->selectmode == SCE_SELECT_EDGE) { | ||||
| BM_edge_select_set(em->bm, l->e, false); | BM_edge_select_set(em->bm, l->e, false); | ||||
| } | } | ||||
| else { | else { | ||||
| BM_vert_select_set(em->bm, l->v, false); | BM_vert_select_set(em->bm, l->v, false); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (!swap) { | if (!swap) { | ||||
| uvedit_face_select_disable(scene, em->bm, efa, cd_loop_uv_offset); | uvedit_face_select_disable(scene, em->bm, efa, offsets); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Flush editmesh selections to ensure valid selection states. */ | /* Flush editmesh selections to ensure valid selection states. */ | ||||
| if (em->selectmode != SCE_SELECT_FACE) { | if (em->selectmode != SCE_SELECT_FACE) { | ||||
| /* NOTE: Make sure correct flags are used. Previously this was done by passing | /* NOTE: Make sure correct flags are used. Previously this was done by passing | ||||
| ▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( | ||||
| scene, view_layer, ((View3D *)NULL), &objects_len); | scene, view_layer, ((View3D *)NULL), &objects_len); | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| Object *ob = objects[ob_index]; | Object *ob = objects[ob_index]; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(ob); | BMEditMesh *em = BKE_editmesh_from_object(ob); | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMLoop *l; | BMLoop *l; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| MLoopUV *luv; | |||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const char *active_uv_name = CustomData_get_active_layer_name(&em->bm->ldata, CD_PROP_FLOAT2); | ||||
| BM_uv_map_ensure_vert_select_attr(em->bm, active_uv_name); | |||||
| BM_uv_map_ensure_edge_select_attr(em->bm, active_uv_name); | |||||
| const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | |||||
| /* NOTE: Selecting faces is delayed so that it doesn't select verts/edges and confuse certain | /* NOTE: Selecting faces is delayed so that it doesn't select verts/edges and confuse certain | ||||
| * UV selection checks. | * UV selection checks. | ||||
| * This creates a temporary state which breaks certain UV selection functions that do face | * This creates a temporary state which breaks certain UV selection functions that do face | ||||
| * visibility checks internally. Current implementation handles each case separately. */ | * visibility checks internally. Current implementation handles each case separately. */ | ||||
| /* call the mesh function if we are in mesh sync sel */ | /* call the mesh function if we are in mesh sync sel */ | ||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | if (ts->uv_flag & UV_SYNC_SELECTION) { | ||||
| Show All 13 Lines | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| * For now we select all UV faces as sticky disabled to ensure proper UV selection states (vert | * For now we select all UV faces as sticky disabled to ensure proper UV selection states (vert | ||||
| * + edge flags) */ | * + edge flags) */ | ||||
| if (use_face_center) { | if (use_face_center) { | ||||
| if (em->selectmode == SCE_SELECT_FACE) { | if (em->selectmode == SCE_SELECT_FACE) { | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| BM_elem_flag_disable(efa, BM_ELEM_TAG); | BM_elem_flag_disable(efa, BM_ELEM_TAG); | ||||
| if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { | if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | BM_ELEM_CD_SET_BOOL(l, offsets.select_vert, select); | ||||
| SET_FLAG_FROM_TEST(luv->flag, select, (MLOOPUV_VERTSEL | MLOOPUV_EDGESEL)); | BM_ELEM_CD_SET_BOOL(l, offsets.select_edge, select); | ||||
| } | } | ||||
| /* BM_face_select_set(em->bm, efa, true); */ | /* BM_face_select_set(em->bm, efa, true); */ | ||||
| BM_elem_flag_enable(efa, BM_ELEM_TAG); | BM_elem_flag_enable(efa, BM_ELEM_TAG); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| BM_elem_flag_disable(efa, BM_ELEM_TAG); | BM_elem_flag_disable(efa, BM_ELEM_TAG); | ||||
| if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { | if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { | ||||
| int totsel = 0; | int totsel = 0; | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| if (em->selectmode == SCE_SELECT_VERTEX) { | if (em->selectmode == SCE_SELECT_VERTEX) { | ||||
| totsel += BM_elem_flag_test(l->v, BM_ELEM_SELECT); | totsel += BM_elem_flag_test(l->v, BM_ELEM_SELECT); | ||||
| } | } | ||||
| else if (em->selectmode == SCE_SELECT_EDGE) { | else if (em->selectmode == SCE_SELECT_EDGE) { | ||||
| totsel += BM_elem_flag_test(l->e, BM_ELEM_SELECT); | totsel += BM_elem_flag_test(l->e, BM_ELEM_SELECT); | ||||
| } | } | ||||
| } | } | ||||
| if (!totsel) { | if (!totsel) { | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | |||||
| SET_FLAG_FROM_TEST(luv->flag, select, (MLOOPUV_VERTSEL | MLOOPUV_EDGESEL)); | BM_ELEM_CD_SET_BOOL(l, offsets.select_vert, select); | ||||
| BM_ELEM_CD_SET_BOOL(l, offsets.select_edge, select); | |||||
| } | } | ||||
| } | } | ||||
| /* BM_face_select_set(em->bm, efa, true); */ | /* BM_face_select_set(em->bm, efa, true); */ | ||||
| BM_elem_flag_enable(efa, BM_ELEM_TAG); | BM_elem_flag_enable(efa, BM_ELEM_TAG); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else if (em->selectmode == SCE_SELECT_FACE) { | else if (em->selectmode == SCE_SELECT_FACE) { | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| BM_elem_flag_disable(efa, BM_ELEM_TAG); | BM_elem_flag_disable(efa, BM_ELEM_TAG); | ||||
| if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { | if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | BM_ELEM_CD_SET_BOOL(l, offsets.select_vert, select); | ||||
| SET_FLAG_FROM_TEST(luv->flag, select, (MLOOPUV_VERTSEL | MLOOPUV_EDGESEL)); | BM_ELEM_CD_SET_BOOL(l, offsets.select_edge, select); | ||||
| } | } | ||||
| /* BM_face_select_set(em->bm, efa, true); */ | /* BM_face_select_set(em->bm, efa, true); */ | ||||
| BM_elem_flag_enable(efa, BM_ELEM_TAG); | BM_elem_flag_enable(efa, BM_ELEM_TAG); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| BM_elem_flag_disable(efa, BM_ELEM_TAG); | BM_elem_flag_disable(efa, BM_ELEM_TAG); | ||||
| if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { | if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | BM_ELEM_CD_SET_BOOL(l, offsets.select_vert, select); | ||||
| SET_FLAG_FROM_TEST(luv->flag, select, (MLOOPUV_VERTSEL | MLOOPUV_EDGESEL)); | BM_ELEM_CD_SET_BOOL(l, offsets.select_edge, select); | ||||
| } | } | ||||
| /* BM_face_select_set(em->bm, efa, true); */ | /* BM_face_select_set(em->bm, efa, true); */ | ||||
| BM_elem_flag_enable(efa, BM_ELEM_TAG); | BM_elem_flag_enable(efa, BM_ELEM_TAG); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* re-select tagged faces */ | /* re-select tagged faces */ | ||||
| ▲ Show 20 Lines • Show All 119 Lines • ▼ Show 20 Lines | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| BMEditMesh *em = me->edit_mesh; | BMEditMesh *em = me->edit_mesh; | ||||
| BMesh *bm = em->bm; | BMesh *bm = em->bm; | ||||
| BMIter iter; | BMIter iter; | ||||
| if (!EDBM_uv_check(em)) { | if (!EDBM_uv_check(em)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | ||||
| bool changed = false; | bool changed = false; | ||||
| BMFace *f; | BMFace *f; | ||||
| BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { | ||||
| if (!uvedit_face_visible_test(scene, f)) { | if (!uvedit_face_visible_test(scene, f)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BMLoop *l_iter; | BMLoop *l_iter; | ||||
| BMLoop *l_first; | BMLoop *l_first; | ||||
| l_iter = l_first = BM_FACE_FIRST_LOOP(f); | l_iter = l_first = BM_FACE_FIRST_LOOP(f); | ||||
| do { | do { | ||||
| if (l_iter == l_iter->radial_next) { | if (l_iter == l_iter->radial_next) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (!uvedit_edge_select_test(scene, l_iter, cd_loop_uv_offset)) { | if (!uvedit_edge_select_test(scene, l_iter, offsets)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| bool mark = false; | bool mark = false; | ||||
| BMLoop *l_other = l_iter->radial_next; | BMLoop *l_other = l_iter->radial_next; | ||||
| do { | do { | ||||
| if (!BM_loop_uv_share_edge_check(l_iter, l_other, cd_loop_uv_offset)) { | if (!BM_loop_uv_share_edge_check(l_iter, l_other, offsets.uv)) { | ||||
| mark = true; | mark = true; | ||||
| break; | break; | ||||
| } | } | ||||
| } while ((l_other = l_other->radial_next) != l_iter); | } while ((l_other = l_other->radial_next) != l_iter); | ||||
| if (mark) { | if (mark) { | ||||
| if (mark_seams) { | if (mark_seams) { | ||||
| BM_elem_flag_enable(l_iter->e, BM_ELEM_SEAM); | BM_elem_flag_enable(l_iter->e, BM_ELEM_SEAM); | ||||
| ▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| Mesh *me = (Mesh *)ob->data; | Mesh *me = (Mesh *)ob->data; | ||||
| BMEditMesh *em = me->edit_mesh; | BMEditMesh *em = me->edit_mesh; | ||||
| BMesh *bm = em->bm; | BMesh *bm = em->bm; | ||||
| if (synced_selection && (bm->totedgesel == 0)) { | if (synced_selection && (bm->totedgesel == 0)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); | const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm); | ||||
| BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { | ||||
| if (uvedit_face_visible_test(scene, efa)) { | if (uvedit_face_visible_test(scene, efa)) { | ||||
| BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| if (uvedit_edge_select_test(scene, loop, cd_loop_uv_offset)) { | if (uvedit_edge_select_test(scene, loop, offsets)) { | ||||
| BM_elem_flag_set(loop->e, BM_ELEM_SEAM, flag_set); | BM_elem_flag_set(loop->e, BM_ELEM_SEAM, flag_set); | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (changed) { | if (changed) { | ||||
| ▲ Show 20 Lines • Show All 148 Lines • Show Last 20 Lines | |||||