Fix T99659: Improve UV Island calculation with hidden faces.

Simplify interface, regularize implementation and some light cleanup.

See also: T79304 and D15419.
This commit is contained in:
Chris Blackbourn 2022-07-13 11:39:06 +12:00
parent d0a552b5c6
commit 8f543a73ab
Notes: blender-bot 2023-05-22 23:42:10 +02:00
Referenced by issue #100075, OBJ import: images loaded multiple times instead of being reused
Referenced by issue #100076, OBJ import: new importer doesn't use //relative/image/paths
Referenced by issue #100017, OBJ: new importer does not import vertices that aren't part of any face
Referenced by issue #99659, UV Island calculation doesn't ignore hidden faces
Referenced by issue #106396, UV editing Stitch crashes Blender with UV sync selection turned on (and hidden faces present))
Referenced by pull request #106493, Fix #106396: UV stitch crash with hidden faces
Referenced by commit 58c54b5859, Fix #106396: UV stitch crash with hidden faces
Referenced by pull request #108130, Fix #108117: Crash in uv editor with hidden geometry
Referenced by commit ae9ac99d2b, Fix #108117: Crash in uv editor with hidden geometry
8 changed files with 57 additions and 68 deletions

View File

@ -69,8 +69,6 @@ typedef struct UvElementMap {
int *islandIndices;
} UvElementMap;
#define INVALID_ISLAND ((unsigned int)-1)
/* Connectivity data */
typedef struct MeshElemMap {
int *indices;

View File

@ -137,7 +137,6 @@ void EDBM_update_extern(struct Mesh *me, bool do_tessellation, bool is_destructi
*/
struct UvElementMap *BM_uv_element_map_create(struct BMesh *bm,
const struct Scene *scene,
bool face_selected,
bool uv_selected,
bool use_winding,
bool do_islands);

View File

@ -593,13 +593,17 @@ UvMapVert *BM_uv_vert_map_at_index(UvVertMap *vmap, uint v)
return vmap->vert[v];
}
#define INVALID_ISLAND ((unsigned int)-1)
UvElementMap *BM_uv_element_map_create(BMesh *bm,
const Scene *scene,
const bool face_selected,
const bool uv_selected,
const bool use_winding,
const bool do_islands)
{
/* In uv sync selection, all UVs are visible. */
const bool face_selected = !(scene->toolsettings->uv_flag & UV_SYNC_SELECTION);
BMVert *ev;
BMFace *efa;
BMLoop *l;
@ -623,15 +627,21 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm,
/* generate UvElement array */
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
if (!face_selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
if (!uv_selected) {
totuv += efa->len;
}
else {
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
totuv++;
}
if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
continue;
}
if (face_selected && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
continue;
}
if (!uv_selected) {
totuv += efa->len;
}
else {
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
totuv++;
}
}
}
@ -649,46 +659,48 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm,
"UvElement");
if (use_winding) {
winding = MEM_mallocN(sizeof(*winding) * totfaces, "winding");
winding = MEM_callocN(sizeof(*winding) * totfaces, "winding");
}
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, j) {
if (use_winding) {
winding[j] = false;
if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
continue;
}
if (!face_selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
float(*tf_uv)[2] = NULL;
if (face_selected && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
continue;
}
float(*tf_uv)[2] = NULL;
if (use_winding) {
tf_uv = (float(*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa->len);
}
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
if (uv_selected && !uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
continue;
}
buf->l = l;
buf->separate = 0;
buf->island = INVALID_ISLAND;
buf->loop_of_poly_index = i;
buf->next = element_map->vert[BM_elem_index_get(l->v)];
element_map->vert[BM_elem_index_get(l->v)] = buf;
if (use_winding) {
tf_uv = (float(*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa->len);
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
copy_v2_v2(tf_uv[i], luv->uv);
}
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
if (uv_selected && !uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
continue;
}
buf++;
}
buf->l = l;
buf->separate = 0;
buf->island = INVALID_ISLAND;
buf->loop_of_poly_index = i;
buf->next = element_map->vert[BM_elem_index_get(l->v)];
element_map->vert[BM_elem_index_get(l->v)] = buf;
if (use_winding) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
copy_v2_v2(tf_uv[i], luv->uv);
}
buf++;
}
if (use_winding) {
winding[j] = cross_poly_v2(tf_uv, efa->len) > 0;
}
if (winding) {
winding[j] = cross_poly_v2(tf_uv, efa->len) > 0;
}
}

View File

@ -500,20 +500,10 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
if (do_island_optimization) {
/* We will need island information */
if (ts->uv_flag & UV_SYNC_SELECTION) {
data->elementMap = BM_uv_element_map_create(bm, scene, false, false, true, true);
}
else {
data->elementMap = BM_uv_element_map_create(bm, scene, true, false, true, true);
}
data->elementMap = BM_uv_element_map_create(bm, scene, false, true, true);
}
else {
if (ts->uv_flag & UV_SYNC_SELECTION) {
data->elementMap = BM_uv_element_map_create(bm, scene, false, false, true, false);
}
else {
data->elementMap = BM_uv_element_map_create(bm, scene, true, false, true, false);
}
data->elementMap = BM_uv_element_map_create(bm, scene, false, true, false);
}
if (!data->elementMap) {

View File

@ -238,7 +238,6 @@ void createTransUVs(bContext *C, TransInfo *t)
{
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = t->scene;
ToolSettings *ts = CTX_data_tool_settings(C);
const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
const bool is_prop_connected = (t->flag & T_PROP_CONNECTED) != 0;
@ -266,8 +265,7 @@ void createTransUVs(bContext *C, TransInfo *t)
/* count */
if (is_island_center) {
/* create element map with island information */
const bool use_facesel = (ts->uv_flag & UV_SYNC_SELECTION) == 0;
elementmap = BM_uv_element_map_create(em->bm, scene, use_facesel, true, false, true);
elementmap = BM_uv_element_map_create(em->bm, scene, true, false, true);
if (elementmap == NULL) {
continue;
}

View File

@ -544,7 +544,7 @@ static bool uvedit_uv_straighten(Scene *scene, BMesh *bm, eUVWeldAlign tool)
return false;
}
UvElementMap *element_map = BM_uv_element_map_create(bm, scene, false, true, false, true);
UvElementMap *element_map = BM_uv_element_map_create(bm, scene, true, false, true);
if (element_map == NULL) {
return false;
}

View File

@ -5223,7 +5223,7 @@ static void uv_isolate_selected_islands(const Scene *scene,
BLI_assert((scene->toolsettings->uv_flag & UV_SYNC_SELECTION) == 0);
BMFace *efa;
BMIter iter, liter;
UvElementMap *elementmap = BM_uv_element_map_create(em->bm, scene, true, false, false, true);
UvElementMap *elementmap = BM_uv_element_map_create(em->bm, scene, false, false, true);
if (elementmap == NULL) {
return;
}

View File

@ -1902,15 +1902,7 @@ static StitchState *stitch_init(bContext *C,
* for stitch this isn't useful behavior, see T86924. */
const int selectmode_orig = scene->toolsettings->selectmode;
scene->toolsettings->selectmode = SCE_SELECT_VERTEX;
/* in uv synch selection, all uv's are visible */
if (ts->uv_flag & UV_SYNC_SELECTION) {
state->element_map = BM_uv_element_map_create(state->em->bm, scene, false, false, true, true);
}
else {
state->element_map = BM_uv_element_map_create(state->em->bm, scene, true, false, true, true);
}
state->element_map = BM_uv_element_map_create(state->em->bm, scene, false, true, true);
scene->toolsettings->selectmode = selectmode_orig;
if (!state->element_map) {