Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/transform/transform_convert_mesh_uv.c
| Show All 20 Lines | |||||
| * \ingroup edtransform | * \ingroup edtransform | ||||
| */ | */ | ||||
| #include "DNA_meshdata_types.h" | #include "DNA_meshdata_types.h" | ||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "BLI_bitmap.h" | #include "BLI_bitmap.h" | ||||
| #include "BLI_linklist_stack.h" | |||||
| #include "BLI_math.h" | #include "BLI_math.h" | ||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||
| #include "BKE_editmesh.h" | #include "BKE_editmesh.h" | ||||
| #include "BKE_mesh_mapping.h" | #include "BKE_mesh_mapping.h" | ||||
| #include "ED_image.h" | #include "ED_image.h" | ||||
| #include "ED_mesh.h" | #include "ED_mesh.h" | ||||
| Show All 9 Lines | |||||
| * | * | ||||
| * \{ */ | * \{ */ | ||||
| static void UVsToTransData(const float aspect[2], | static void UVsToTransData(const float aspect[2], | ||||
| TransData *td, | TransData *td, | ||||
| TransData2D *td2d, | TransData2D *td2d, | ||||
| float *uv, | float *uv, | ||||
| const float *center, | const float *center, | ||||
| float calc_dist, | |||||
| bool selected) | bool selected) | ||||
| { | { | ||||
| /* uv coords are scaled by aspects. this is needed for rotations and | /* uv coords are scaled by aspects. this is needed for rotations and | ||||
| * proportional editing to be consistent with the stretched uv coords | * proportional editing to be consistent with the stretched uv coords | ||||
| * that are displayed. this also means that for display and numinput, | * that are displayed. this also means that for display and numinput, | ||||
| * and when the uv coords are flushed, these are converted each time */ | * and when the uv coords are flushed, these are converted each time */ | ||||
| td2d->loc[0] = uv[0] * aspect[0]; | td2d->loc[0] = uv[0] * aspect[0]; | ||||
| td2d->loc[1] = uv[1] * aspect[1]; | td2d->loc[1] = uv[1] * aspect[1]; | ||||
| Show All 12 Lines | static void UVsToTransData(const float aspect[2], | ||||
| td->ext = NULL; | td->ext = NULL; | ||||
| td->val = NULL; | td->val = NULL; | ||||
| if (selected) { | if (selected) { | ||||
| td->flag |= TD_SELECTED; | td->flag |= TD_SELECTED; | ||||
| td->dist = 0.0; | td->dist = 0.0; | ||||
| } | } | ||||
| else { | else { | ||||
| td->dist = FLT_MAX; | td->dist = calc_dist; | ||||
| } | } | ||||
| unit_m3(td->mtx); | unit_m3(td->mtx); | ||||
| unit_m3(td->smtx); | unit_m3(td->smtx); | ||||
| } | } | ||||
| /** | |||||
| * \param dists: Store the closest connected distance to selected vertices. | |||||
| */ | |||||
| static void uv_set_connectivity_distance(BMesh *bm, float *dists, const float aspect[2]) | |||||
| { | |||||
| /* Mostly copied from editmesh_set_connectivity_distance. */ | |||||
| BLI_LINKSTACK_DECLARE(queue, BMLoop *); | |||||
| /* any BM_ELEM_TAG'd vertex is in 'queue_next', so we don't add in twice */ | |||||
campbellbarton: Picky - use full sentences. | |||||
| BLI_LINKSTACK_DECLARE(queue_next, BMLoop *); | |||||
| BLI_LINKSTACK_INIT(queue); | |||||
| BLI_LINKSTACK_INIT(queue_next); | |||||
| const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); | |||||
| BMIter fiter, liter; | |||||
| BMVert *f; | |||||
| BMLoop *l; | |||||
| BM_mesh_elem_index_ensure(bm, BM_LOOP); | |||||
| BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { | |||||
| /* Visable faces was tagged in createTransUVs. */ | |||||
| if (!BM_elem_flag_test(f, BM_ELEM_TAG)) { | |||||
| continue; | |||||
| } | |||||
| BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { | |||||
| float dist; | |||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | |||||
| bool uv_vert_sel = luv->flag & MLOOPUV_VERTSEL; | |||||
| if (uv_vert_sel) { | |||||
| BLI_LINKSTACK_PUSH(queue, l); | |||||
| dist = 0.0f; | |||||
| } | |||||
| else { | |||||
| dist = FLT_MAX; | |||||
| } | |||||
| /* Make sure all loops are in a clean tag state. */ | |||||
| BM_elem_flag_disable(l, BM_ELEM_TAG); | |||||
| int loop_idx = BM_elem_index_get(l); | |||||
| dists[loop_idx] = dist; | |||||
| } | |||||
| } | |||||
| /* need to be very careful of feedback loops here, store previous dist's to avoid feedback */ | |||||
| float *dists_prev = MEM_dupallocN(dists); | |||||
| do { | |||||
| while ((l = BLI_LINKSTACK_POP(queue))) { | |||||
| BLI_assert(dists[BM_elem_index_get(l)] != FLT_MAX); | |||||
| BMLoop *l_other, *l_con; | |||||
| BMIter l_con_iter; | |||||
campbellbartonUnsubmitted Done Inline Actionscon abbreviation is a bit ambiguous (could use connected or adjacent). campbellbarton: `con` abbreviation is a bit ambiguous (could use `connected` or `adjacent`). | |||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | |||||
| float l_uv[2]; | |||||
| copy_v2_v2(l_uv, luv->uv); | |||||
| mul_v2_v2(l_uv, aspect); | |||||
| BM_ITER_ELEM (l_other, &liter, l->f, BM_LOOPS_OF_FACE) { | |||||
| if (l_other == l) { | |||||
| continue; | |||||
| } | |||||
| float other_uv[2], edge_vec[2]; | |||||
| MLoopUV *luv_other = BM_ELEM_CD_GET_VOID_P(l_other, cd_loop_uv_offset); | |||||
| copy_v2_v2(other_uv, luv_other->uv); | |||||
| mul_v2_v2(other_uv, aspect); | |||||
| sub_v2_v2v2(edge_vec, l_uv, other_uv); | |||||
| const int i = BM_elem_index_get(l); | |||||
| const int i_other = BM_elem_index_get(l_other); | |||||
| float dist = len_v2(edge_vec) + dists_prev[i]; | |||||
| if (dist < dists[i_other]) { | |||||
| dists[i_other] = dist; | |||||
| } | |||||
| else { | |||||
| /* The face loop already has a shorter path to it. */ | |||||
| continue; | |||||
| } | |||||
| float con_uv[2]; | |||||
| float uvdiff[2]; | |||||
| bool other_vert_sel, con_vert_sel; | |||||
| other_vert_sel = luv_other->flag & MLOOPUV_VERTSEL; | |||||
| BM_ITER_ELEM (l_con, &l_con_iter, l_other->v, BM_LOOPS_OF_VERT) { | |||||
| if (l_con == l_other) { | |||||
| continue; | |||||
| } | |||||
| /* Visable faces was tagged in createTransUVs. */ | |||||
| if (!BM_elem_flag_test(l_con->f, BM_ELEM_TAG)) { | |||||
| continue; | |||||
| } | |||||
| MLoopUV *luv_con = BM_ELEM_CD_GET_VOID_P(l_con, cd_loop_uv_offset); | |||||
| con_vert_sel = luv_con->flag & MLOOPUV_VERTSEL; | |||||
| copy_v2_v2(con_uv, luv_con->uv); | |||||
| mul_v2_v2(con_uv, aspect); | |||||
| sub_v2_v2v2(uvdiff, con_uv, other_uv); | |||||
| /* Check if this loop is connected in UV space. | |||||
| * If the uv loops share the same selection state (if not, they are not connected as | |||||
| * they have been ripped or other edit commands have seperated them). */ | |||||
| bool connected = other_vert_sel == con_vert_sel && | |||||
| fabsf(uvdiff[0]) < STD_UV_CONNECT_LIMIT && | |||||
| fabsf(uvdiff[1]) < STD_UV_CONNECT_LIMIT; | |||||
| if (!connected) { | |||||
| continue; | |||||
| } | |||||
| /* The loop vert is occupying the same space, so it has the same distance. */ | |||||
| const int i_con = BM_elem_index_get(l_con); | |||||
| dists[i_con] = dist; | |||||
| if (BM_elem_flag_test(l_con, BM_ELEM_TAG) == 0) { | |||||
| BM_elem_flag_enable(l_con, BM_ELEM_TAG); | |||||
| BLI_LINKSTACK_PUSH(queue_next, l_con); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| /* clear for the next loop */ | |||||
| for (LinkNode *lnk = queue_next; lnk; lnk = lnk->next) { | |||||
| BMLoop *l_link = lnk->link; | |||||
| const int i = BM_elem_index_get(l_link); | |||||
| BM_elem_flag_disable(l_link, BM_ELEM_TAG); | |||||
| /* keep in sync, avoid having to do full memcpy each iteration */ | |||||
campbellbartonUnsubmitted Done Inline Actionspicky (again sentences) campbellbarton: picky (again sentences) | |||||
| dists_prev[i] = dists[i]; | |||||
| } | |||||
| BLI_LINKSTACK_SWAP(queue, queue_next); | |||||
| } while (BLI_LINKSTACK_SIZE(queue)); | |||||
| BLI_LINKSTACK_FREE(queue); | |||||
| BLI_LINKSTACK_FREE(queue_next); | |||||
| MEM_freeN(dists_prev); | |||||
| } | |||||
| void createTransUVs(bContext *C, TransInfo *t) | void createTransUVs(bContext *C, TransInfo *t) | ||||
| { | { | ||||
| SpaceImage *sima = CTX_wm_space_image(C); | SpaceImage *sima = CTX_wm_space_image(C); | ||||
| Scene *scene = t->scene; | Scene *scene = t->scene; | ||||
| ToolSettings *ts = CTX_data_tool_settings(C); | ToolSettings *ts = CTX_data_tool_settings(C); | ||||
| const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; | const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; | ||||
| const bool is_prop_connected = (t->flag & T_PROP_CONNECTED) != 0; | const bool is_prop_connected = (t->flag & T_PROP_CONNECTED) != 0; | ||||
| const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS); | const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS); | ||||
| FOREACH_TRANS_DATA_CONTAINER (t, tc) { | FOREACH_TRANS_DATA_CONTAINER (t, tc) { | ||||
| TransData *td = NULL; | TransData *td = NULL; | ||||
| TransData2D *td2d = NULL; | TransData2D *td2d = NULL; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); | BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); | ||||
| BMFace *efa; | BMFace *efa; | ||||
| BMIter iter, liter; | BMIter iter, liter; | ||||
| UvElementMap *elementmap = NULL; | UvElementMap *elementmap = NULL; | ||||
| BLI_bitmap *island_enabled = NULL; | |||||
| struct { | struct { | ||||
| float co[2]; | float co[2]; | ||||
| int co_num; | int co_num; | ||||
| } *island_center = NULL; | } *island_center = NULL; | ||||
| int count = 0, countsel = 0, count_rejected = 0; | int count = 0, countsel = 0; | ||||
| const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); | ||||
| if (!ED_space_image_show_uvedit(sima, tc->obedit)) { | if (!ED_space_image_show_uvedit(sima, tc->obedit)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* count */ | /* count */ | ||||
| if (is_prop_connected || is_island_center) { | if (is_island_center) { | ||||
| /* create element map with island information */ | /* create element map with island information */ | ||||
| const bool use_facesel = (ts->uv_flag & UV_SYNC_SELECTION) == 0; | const bool use_facesel = (ts->uv_flag & UV_SYNC_SELECTION) == 0; | ||||
| const bool use_uvsel = !is_prop_connected; | elementmap = BM_uv_element_map_create(em->bm, scene, use_facesel, true, false, true); | ||||
| elementmap = BM_uv_element_map_create(em->bm, scene, use_facesel, use_uvsel, false, true); | |||||
| if (elementmap == NULL) { | if (elementmap == NULL) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (is_prop_connected) { | |||||
| island_enabled = BLI_BITMAP_NEW(elementmap->totalIslands, "TransIslandData(UV Editing)"); | |||||
| } | |||||
| if (is_island_center) { | |||||
| island_center = MEM_callocN(sizeof(*island_center) * elementmap->totalIslands, __func__); | island_center = MEM_callocN(sizeof(*island_center) * elementmap->totalIslands, __func__); | ||||
| } | } | ||||
| } | |||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| BMLoop *l; | BMLoop *l; | ||||
| if (!uvedit_face_visible_test(scene, efa)) { | if (!uvedit_face_visible_test(scene, efa)) { | ||||
| BM_elem_flag_disable(efa, BM_ELEM_TAG); | BM_elem_flag_disable(efa, BM_ELEM_TAG); | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_elem_flag_enable(efa, BM_ELEM_TAG); | BM_elem_flag_enable(efa, BM_ELEM_TAG); | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { | if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { | ||||
| countsel++; | countsel++; | ||||
| if (is_prop_connected || island_center) { | if (island_center) { | ||||
| UvElement *element = BM_uv_element_get(elementmap, efa, l); | UvElement *element = BM_uv_element_get(elementmap, efa, l); | ||||
| if (is_prop_connected) { | |||||
| BLI_BITMAP_ENABLE(island_enabled, element->island); | |||||
| } | |||||
| if (is_island_center) { | |||||
| if (element->flag == false) { | if (element->flag == false) { | ||||
| MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | ||||
| add_v2_v2(island_center[element->island].co, luv->uv); | add_v2_v2(island_center[element->island].co, luv->uv); | ||||
| island_center[element->island].co_num++; | island_center[element->island].co_num++; | ||||
| element->flag = true; | element->flag = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| if (is_prop_edit) { | if (is_prop_edit) { | ||||
| count++; | count++; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Support other objects using PET to adjust these, unless connected is enabled. */ | /* Support other objects using PET to adjust these, unless connected is enabled. */ | ||||
| Show All 18 Lines | FOREACH_TRANS_DATA_CONTAINER (t, tc) { | ||||
| if (sima->flag & SI_CLIP_UV) { | if (sima->flag & SI_CLIP_UV) { | ||||
| t->flag |= T_CLIP_UV; | t->flag |= T_CLIP_UV; | ||||
| } | } | ||||
| td = tc->data; | td = tc->data; | ||||
| td2d = tc->data_2d; | td2d = tc->data_2d; | ||||
| float *prop_dists = NULL; | |||||
| if (is_prop_connected) { | |||||
| prop_dists = MEM_callocN(em->bm->totloop * sizeof(float), "TransObPropDists(UV Editing)"); | |||||
| uv_set_connectivity_distance(em->bm, prop_dists, t->aspect); | |||||
| } | |||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| BMLoop *l; | BMLoop *l; | ||||
| if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) { | if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { | ||||
| const bool selected = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); | const bool selected = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); | ||||
| MLoopUV *luv; | MLoopUV *luv; | ||||
| const float *center = NULL; | const float *center = NULL; | ||||
| float prop_distance = FLT_MAX; | |||||
| if (!is_prop_edit && !selected) { | if (!is_prop_edit && !selected) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (is_prop_connected || is_island_center) { | |||||
| UvElement *element = BM_uv_element_get(elementmap, efa, l); | |||||
| if (element) { | |||||
| if (is_prop_connected) { | if (is_prop_connected) { | ||||
| if (!BLI_BITMAP_TEST(island_enabled, element->island)) { | const int idx = BM_elem_index_get(l); | ||||
| count_rejected++; | prop_distance = prop_dists[idx]; | ||||
| continue; | |||||
| } | |||||
| } | } | ||||
| if (is_island_center) { | if (is_island_center) { | ||||
| UvElement *element = BM_uv_element_get(elementmap, efa, l); | |||||
| if (element) { | |||||
| center = island_center[element->island].co; | center = island_center[element->island].co; | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| BM_elem_flag_enable(l, BM_ELEM_TAG); | BM_elem_flag_enable(l, BM_ELEM_TAG); | ||||
| luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); | ||||
| UVsToTransData(t->aspect, td++, td2d++, luv->uv, center, selected); | UVsToTransData(t->aspect, td++, td2d++, luv->uv, center, prop_distance, selected); | ||||
| } | } | ||||
| } | } | ||||
| if (is_prop_connected) { | |||||
| tc->data_len -= count_rejected; | |||||
| } | |||||
| if (sima->flag & SI_LIVE_UNWRAP) { | if (sima->flag & SI_LIVE_UNWRAP) { | ||||
| ED_uvedit_live_unwrap_begin(t->scene, tc->obedit); | ED_uvedit_live_unwrap_begin(t->scene, tc->obedit); | ||||
| } | } | ||||
| finally: | finally: | ||||
| if (is_prop_connected || is_island_center) { | |||||
| BM_uv_element_map_free(elementmap); | |||||
| if (is_prop_connected) { | if (is_prop_connected) { | ||||
| MEM_freeN(island_enabled); | MEM_freeN(prop_dists); | ||||
| } | } | ||||
| if (is_island_center) { | |||||
| BM_uv_element_map_free(elementmap); | |||||
| if (island_center) { | |||||
| MEM_freeN(island_center); | MEM_freeN(island_center); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name UVs Transform Flush | /** \name UVs Transform Flush | ||||
| * | * | ||||
| * \{ */ | * \{ */ | ||||
| ▲ Show 20 Lines • Show All 66 Lines • Show Last 20 Lines | |||||
Picky - use full sentences.