UV: Deduplicate code that traverses each UV
The algorithm that traverses UV is a bit complex and is being iterated a lot in different areas of the code. This commit deduplicates this code by creating a foreach UV function. At the moment only the `uvedit_ops.cc` file uses this function but similar cleanups can also be done on many other files that use UVs.
This commit is contained in:
@@ -41,6 +41,17 @@ void ED_keymap_uvedit(wmKeyConfig *keyconf);
|
||||
*/
|
||||
void ED_uvedit_select_all(BMesh *bm);
|
||||
|
||||
void ED_uvedit_foreach_uv(const Scene *scene,
|
||||
BMesh *bm,
|
||||
const bool skip_invisible,
|
||||
const bool selected,
|
||||
blender::FunctionRef<void(float[2])> user_fn);
|
||||
void ED_uvedit_foreach_uv_multi(const Scene *scene,
|
||||
Object **objects_edit,
|
||||
uint objects_len,
|
||||
const bool skip_invisible,
|
||||
const bool skip_nonselected,
|
||||
blender::FunctionRef<void(float[2])> user_fn);
|
||||
bool ED_uvedit_minmax_multi(
|
||||
const Scene *scene, Object **objects_edit, uint objects_len, float r_min[2], float r_max[2]);
|
||||
bool ED_uvedit_center_multi(
|
||||
|
||||
@@ -59,6 +59,8 @@
|
||||
|
||||
#include "uvedit_intern.h"
|
||||
|
||||
using namespace blender;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name State Testing
|
||||
* \{ */
|
||||
@@ -192,37 +194,61 @@ void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit)
|
||||
/** \name Geometric Utilities
|
||||
* \{ */
|
||||
|
||||
void ED_uvedit_foreach_uv(const Scene *scene,
|
||||
BMesh *bm,
|
||||
const bool skip_invisible,
|
||||
const bool selected,
|
||||
FunctionRef<void(float[2])> user_fn)
|
||||
{
|
||||
/* Check selection for quick return. */
|
||||
const bool synced_selection = (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
|
||||
if (synced_selection && (bm->totvertsel == selected ? 0 : bm->totvert)) {
|
||||
return;
|
||||
}
|
||||
|
||||
BMFace *efa;
|
||||
BMLoop *l;
|
||||
BMIter iter, liter;
|
||||
|
||||
const BMUVOffsets offsets = BM_uv_map_get_offsets(bm);
|
||||
|
||||
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
|
||||
if (skip_invisible && !uvedit_face_visible_test(scene, efa)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
|
||||
if (uvedit_uv_select_test(scene, l, offsets) == selected) {
|
||||
float *luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv);
|
||||
user_fn(luv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ED_uvedit_foreach_uv_multi(const Scene *scene,
|
||||
Object **objects_edit,
|
||||
uint objects_len,
|
||||
const bool skip_invisible,
|
||||
const bool skip_nonselected,
|
||||
FunctionRef<void(float[2])> user_fn)
|
||||
{
|
||||
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
||||
Object *obedit = objects_edit[ob_index];
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
ED_uvedit_foreach_uv(scene, em->bm, skip_invisible, skip_nonselected, user_fn);
|
||||
}
|
||||
}
|
||||
|
||||
bool ED_uvedit_minmax_multi(
|
||||
const Scene *scene, Object **objects_edit, uint objects_len, float r_min[2], float r_max[2])
|
||||
{
|
||||
bool changed = false;
|
||||
INIT_MINMAX2(r_min, r_max);
|
||||
|
||||
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
||||
Object *obedit = objects_edit[ob_index];
|
||||
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
BMFace *efa;
|
||||
BMLoop *l;
|
||||
BMIter iter, liter;
|
||||
float *luv;
|
||||
|
||||
const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm);
|
||||
|
||||
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
||||
if (!uvedit_face_visible_test(scene, efa)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
|
||||
if (uvedit_uv_select_test(scene, l, offsets)) {
|
||||
luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv);
|
||||
minmax_v2v2_v2(r_min, r_max, luv);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ED_uvedit_foreach_uv_multi(scene, objects_edit, objects_len, true, true, [&](float luv[2]) {
|
||||
minmax_v2v2_v2(r_min, r_max, luv);
|
||||
changed = true;
|
||||
});
|
||||
return changed;
|
||||
}
|
||||
|
||||
@@ -249,31 +275,10 @@ static bool ED_uvedit_median_multi(const Scene *scene,
|
||||
uint sel = 0;
|
||||
zero_v2(co);
|
||||
|
||||
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
||||
Object *obedit = objects_edit[ob_index];
|
||||
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
BMFace *efa;
|
||||
BMLoop *l;
|
||||
BMIter iter, liter;
|
||||
float *luv;
|
||||
|
||||
const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm);
|
||||
|
||||
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
||||
if (!uvedit_face_visible_test(scene, efa)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
|
||||
luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv);
|
||||
if (uvedit_uv_select_test(scene, l, offsets)) {
|
||||
add_v2_v2(co, luv);
|
||||
sel++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ED_uvedit_foreach_uv_multi(scene, objects_edit, objects_len, true, true, [&](float luv[2]) {
|
||||
add_v2_v2(co, luv);
|
||||
sel++;
|
||||
});
|
||||
|
||||
mul_v2_fl(co, 1.0f / float(sel));
|
||||
|
||||
@@ -359,36 +364,22 @@ static bool uvedit_uv_align_weld(Scene *scene,
|
||||
const float cent[2])
|
||||
{
|
||||
bool changed = false;
|
||||
const BMUVOffsets offsets = BM_uv_map_get_offsets(bm);
|
||||
|
||||
BMIter iter;
|
||||
BMFace *efa;
|
||||
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
|
||||
if (!uvedit_face_visible_test(scene, efa)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BMIter liter;
|
||||
BMLoop *l;
|
||||
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
|
||||
if (!uvedit_uv_select_test(scene, l, offsets)) {
|
||||
continue;
|
||||
}
|
||||
float *luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv);
|
||||
if (ELEM(tool, UV_ALIGN_X, UV_WELD)) {
|
||||
if (luv[0] != cent[0]) {
|
||||
luv[0] = cent[0];
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (ELEM(tool, UV_ALIGN_Y, UV_WELD)) {
|
||||
if (luv[1] != cent[1]) {
|
||||
luv[1] = cent[1];
|
||||
changed = true;
|
||||
}
|
||||
ED_uvedit_foreach_uv(scene, bm, true, true, [&](float luv[2]) {
|
||||
if (ELEM(tool, UV_ALIGN_X, UV_WELD)) {
|
||||
if (luv[0] != cent[0]) {
|
||||
luv[0] = cent[0];
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ELEM(tool, UV_ALIGN_Y, UV_WELD)) {
|
||||
if (luv[1] != cent[1]) {
|
||||
luv[1] = cent[1];
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
@@ -561,33 +552,9 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
|
||||
scene, view_layer, ((View3D *)nullptr), &objects_len);
|
||||
|
||||
if (tool == UV_ALIGN_AUTO) {
|
||||
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
||||
Object *obedit = objects[ob_index];
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
|
||||
if (synced_selection && (em->bm->totvertsel == 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm);
|
||||
|
||||
BMIter iter, liter;
|
||||
BMFace *efa;
|
||||
BMLoop *l;
|
||||
|
||||
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
||||
if (!uvedit_face_visible_test(scene, efa)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
|
||||
if (uvedit_uv_select_test(scene, l, offsets)) {
|
||||
float *luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv);
|
||||
minmax_v2v2_v2(min, max, luv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ED_uvedit_foreach_uv_multi(scene, objects, objects_len, true, true, [&](float luv[2]) {
|
||||
minmax_v2v2_v2(min, max, luv);
|
||||
});
|
||||
tool = (max[0] - min[0] >= max[1] - min[1]) ? UV_ALIGN_Y : UV_ALIGN_X;
|
||||
}
|
||||
|
||||
@@ -718,33 +685,14 @@ static int uv_remove_doubles_to_selected(bContext *C, wmOperator *op)
|
||||
int mloopuv_count = 0; /* Also used for *duplicates count. */
|
||||
|
||||
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
||||
BMIter iter, liter;
|
||||
BMFace *efa;
|
||||
BMLoop *l;
|
||||
Object *obedit = objects[ob_index];
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
|
||||
if (synced_selection && (em->bm->totvertsel == 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm);
|
||||
|
||||
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
||||
if (!uvedit_face_visible_test(scene, efa)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
|
||||
if (uvedit_uv_select_test(scene, l, offsets)) {
|
||||
float *luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv);
|
||||
BLI_kdtree_2d_insert(tree, mloopuv_count, luv);
|
||||
duplicates.append(-1);
|
||||
mloopuv_arr.append(luv);
|
||||
mloopuv_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
ED_uvedit_foreach_uv(scene, em->bm, true, true, [&](float luv[2]) {
|
||||
BLI_kdtree_2d_insert(tree, mloopuv_count, luv);
|
||||
duplicates.append(-1);
|
||||
mloopuv_arr.append(luv);
|
||||
mloopuv_count++;
|
||||
});
|
||||
|
||||
ob_mloopuv_max_idx[ob_index] = mloopuv_count - 1;
|
||||
}
|
||||
@@ -845,70 +793,28 @@ static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op)
|
||||
int mloopuv_count = 0;
|
||||
|
||||
/* Add visible non-selected uvs to tree */
|
||||
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
||||
BMIter iter, liter;
|
||||
BMFace *efa;
|
||||
BMLoop *l;
|
||||
Object *obedit = objects[ob_index];
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
|
||||
if (synced_selection && (em->bm->totvertsel == em->bm->totvert)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm);
|
||||
|
||||
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
||||
if (!uvedit_face_visible_test(scene, efa)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
|
||||
if (!uvedit_uv_select_test(scene, l, offsets)) {
|
||||
float *luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv);
|
||||
BLI_kdtree_2d_insert(tree, mloopuv_count, luv);
|
||||
mloopuv_arr.append(luv);
|
||||
mloopuv_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ED_uvedit_foreach_uv_multi(scene, objects, objects_len, true, false, [&](float luv[2]) {
|
||||
BLI_kdtree_2d_insert(tree, mloopuv_count, luv);
|
||||
mloopuv_arr.append(luv);
|
||||
mloopuv_count++;
|
||||
});
|
||||
|
||||
BLI_kdtree_2d_balance(tree);
|
||||
|
||||
/* For each selected uv, find duplicate non selected uv. */
|
||||
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
||||
BMIter iter, liter;
|
||||
BMFace *efa;
|
||||
BMLoop *l;
|
||||
bool changed = false;
|
||||
Object *obedit = objects[ob_index];
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
ED_uvedit_foreach_uv(scene, em->bm, true, true, [&](float luv[2]) {
|
||||
KDTreeNearest_2d nearest;
|
||||
const int i = BLI_kdtree_2d_find_nearest(tree, luv, &nearest);
|
||||
|
||||
if (synced_selection && (em->bm->totvertsel == 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm);
|
||||
|
||||
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
||||
if (!uvedit_face_visible_test(scene, efa)) {
|
||||
continue;
|
||||
if (i != -1 && nearest.dist < threshold) {
|
||||
copy_v2_v2(luv, mloopuv_arr[i]);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
|
||||
if (uvedit_uv_select_test(scene, l, offsets)) {
|
||||
float *luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv);
|
||||
KDTreeNearest_2d nearest;
|
||||
const int i = BLI_kdtree_2d_find_nearest(tree, luv, &nearest);
|
||||
|
||||
if (i != -1 && nearest.dist < threshold) {
|
||||
copy_v2_v2(luv, mloopuv_arr[i]);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (changed) {
|
||||
uvedit_live_unwrap_update(sima, scene, obedit);
|
||||
@@ -1096,21 +1002,10 @@ static bool uv_snap_uvs_to_cursor(Scene *scene, Object *obedit, const float curs
|
||||
float *luv;
|
||||
bool changed = false;
|
||||
|
||||
const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm);
|
||||
|
||||
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
||||
if (!uvedit_face_visible_test(scene, efa)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
|
||||
if (uvedit_uv_select_test(scene, l, offsets)) {
|
||||
luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv);
|
||||
copy_v2_v2(luv, cursor);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
ED_uvedit_foreach_uv(scene, em->bm, true, true, [&](float luv[2]) {
|
||||
copy_v2_v2(luv, cursor);
|
||||
changed = true;
|
||||
});
|
||||
|
||||
return changed;
|
||||
}
|
||||
@@ -1124,21 +1019,10 @@ static bool uv_snap_uvs_offset(Scene *scene, Object *obedit, const float offset[
|
||||
float *luv;
|
||||
bool changed = false;
|
||||
|
||||
const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm);
|
||||
|
||||
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
||||
if (!uvedit_face_visible_test(scene, efa)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
|
||||
if (uvedit_uv_select_test(scene, l, offsets)) {
|
||||
luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv);
|
||||
add_v2_v2(luv, offset);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
ED_uvedit_foreach_uv(scene, em->bm, true, true, [&](float luv[2]) {
|
||||
add_v2_v2(luv, offset);
|
||||
changed = true;
|
||||
});
|
||||
|
||||
return changed;
|
||||
}
|
||||
@@ -1209,26 +1093,14 @@ static bool uv_snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit
|
||||
float w, h;
|
||||
bool changed = false;
|
||||
|
||||
const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm);
|
||||
|
||||
ED_space_image_get_size(sima, &width, &height);
|
||||
w = float(width);
|
||||
h = float(height);
|
||||
|
||||
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
||||
if (!uvedit_face_visible_test(scene, efa)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
|
||||
if (uvedit_uv_select_test(scene, l, offsets)) {
|
||||
luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv);
|
||||
uv_snap_to_pixel(luv, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
ED_uvedit_foreach_uv(scene, em->bm, true, true, [&](float luv[2]) {
|
||||
uv_snap_to_pixel(luv, w, h);
|
||||
changed = true;
|
||||
}
|
||||
});
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user