diff options
Diffstat (limited to 'source/blender/editors/uvedit/uvedit_smart_stitch.c')
-rw-r--r-- | source/blender/editors/uvedit/uvedit_smart_stitch.c | 4920 |
1 files changed, 2501 insertions, 2419 deletions
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index 91167e247f4..71a3fdf055e 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -21,7 +21,6 @@ * \ingroup eduv */ - #include <stdlib.h> #include <string.h> #include <math.h> @@ -73,26 +72,25 @@ /* object that stores display data for previewing before confirming stitching */ typedef struct StitchPreviewer { - /* here we'll store the preview triangle indices of the mesh */ - float *preview_polys; - /* uvs per polygon. */ - unsigned int *uvs_per_polygon; - /*number of preview polygons */ - unsigned int num_polys; - /* preview data. These will be either the previewed vertices or edges - * depending on stitch mode settings */ - float *preview_stitchable; - float *preview_unstitchable; - /* here we'll store the number of elements to be drawn */ - unsigned int num_stitchable; - unsigned int num_unstitchable; - unsigned int preview_uvs; - /* ...and here we'll store the static island triangles */ - float *static_tris; - unsigned int num_static_tris; + /* here we'll store the preview triangle indices of the mesh */ + float *preview_polys; + /* uvs per polygon. */ + unsigned int *uvs_per_polygon; + /*number of preview polygons */ + unsigned int num_polys; + /* preview data. These will be either the previewed vertices or edges + * depending on stitch mode settings */ + float *preview_stitchable; + float *preview_unstitchable; + /* here we'll store the number of elements to be drawn */ + unsigned int num_stitchable; + unsigned int num_unstitchable; + unsigned int preview_uvs; + /* ...and here we'll store the static island triangles */ + float *static_tris; + unsigned int num_static_tris; } StitchPreviewer; - struct IslandStitchData; /** @@ -101,115 +99,114 @@ struct IslandStitchData; * elements of the island except from the stitchable. */ typedef struct IslandStitchData { - /* rotation can be used only for edges, for vertices there is no such notion */ - float rotation; - float rotation_neg; - float translation[2]; - /* Used for rotation, the island will rotate around this point */ - float medianPoint[2]; - int numOfElements; - int num_rot_elements; - int num_rot_elements_neg; - /* flag to remember if island has been added for preview */ - char addedForPreview; - /* flag an island to be considered for determining static island */ - char stitchableCandidate; - /* if edge rotation is used, flag so that vertex rotation is not used */ - bool use_edge_rotation; + /* rotation can be used only for edges, for vertices there is no such notion */ + float rotation; + float rotation_neg; + float translation[2]; + /* Used for rotation, the island will rotate around this point */ + float medianPoint[2]; + int numOfElements; + int num_rot_elements; + int num_rot_elements_neg; + /* flag to remember if island has been added for preview */ + char addedForPreview; + /* flag an island to be considered for determining static island */ + char stitchableCandidate; + /* if edge rotation is used, flag so that vertex rotation is not used */ + bool use_edge_rotation; } IslandStitchData; /* just for averaging UVs */ typedef struct UVVertAverage { - float uv[2]; - unsigned short count; + float uv[2]; + unsigned short count; } UVVertAverage; typedef struct UvEdge { - /** index to uv buffer */ - unsigned int uv1; - unsigned int uv2; - /** general use flag - * (Used to check if edge is boundary here, and propagates to adjacency elements) */ - unsigned char flag; - /** element that guarantees element->face - * has the edge on element->tfindex and element->tfindex+1 is the second uv */ - UvElement *element; - /** next uv edge with the same exact vertices as this one. - * Calculated at startup to save time */ - struct UvEdge *next; - /** point to first of common edges. Needed for iteration */ - struct UvEdge *first; + /** index to uv buffer */ + unsigned int uv1; + unsigned int uv2; + /** general use flag + * (Used to check if edge is boundary here, and propagates to adjacency elements) */ + unsigned char flag; + /** element that guarantees element->face + * has the edge on element->tfindex and element->tfindex+1 is the second uv */ + UvElement *element; + /** next uv edge with the same exact vertices as this one. + * Calculated at startup to save time */ + struct UvEdge *next; + /** point to first of common edges. Needed for iteration */ + struct UvEdge *first; } UvEdge; - /* stitch state object */ typedef struct StitchState { - float aspect; - /* object for editmesh */ - Object *obedit; - /* editmesh, cached for use in modal handler */ - BMEditMesh *em; - - /* element map for getting info about uv connectivity */ - UvElementMap *element_map; - /* edge container */ - UvEdge *uvedges; - /* container of first of a group of coincident uvs, these will be operated upon */ - UvElement **uvs; - /* maps uvelements to their first coincident uv */ - int *map; - /* 2D normals per uv to calculate rotation for snapping */ - float *normals; - /* edge storage */ - UvEdge *edges; - /* hash for quick lookup of edges */ - GHash *edge_hash; - /* which islands to stop at (to make active) when pressing 'I' */ - bool *island_is_stitchable; - - /* count of separate uvs and edges */ - int total_separate_edges; - int total_separate_uvs; - /* hold selection related information */ - void **selection_stack; - int selection_size; - - /* store number of primitives per face so that we can allocate the active island buffer later */ - unsigned int *tris_per_island; - /* preview data */ - StitchPreviewer *stitch_preview; + float aspect; + /* object for editmesh */ + Object *obedit; + /* editmesh, cached for use in modal handler */ + BMEditMesh *em; + + /* element map for getting info about uv connectivity */ + UvElementMap *element_map; + /* edge container */ + UvEdge *uvedges; + /* container of first of a group of coincident uvs, these will be operated upon */ + UvElement **uvs; + /* maps uvelements to their first coincident uv */ + int *map; + /* 2D normals per uv to calculate rotation for snapping */ + float *normals; + /* edge storage */ + UvEdge *edges; + /* hash for quick lookup of edges */ + GHash *edge_hash; + /* which islands to stop at (to make active) when pressing 'I' */ + bool *island_is_stitchable; + + /* count of separate uvs and edges */ + int total_separate_edges; + int total_separate_uvs; + /* hold selection related information */ + void **selection_stack; + int selection_size; + + /* store number of primitives per face so that we can allocate the active island buffer later */ + unsigned int *tris_per_island; + /* preview data */ + StitchPreviewer *stitch_preview; } StitchState; /* Stitch state container. */ typedef struct StitchStateContainer { - /* clear seams of stitched edges after stitch */ - bool clear_seams; - /* use limit flag */ - bool use_limit; - /* limit to operator, same as original operator */ - float limit_dist; - /* snap uv islands together during stitching */ - bool snap_islands; - /* stitch at midpoints or at islands */ - bool midpoints; - /* vert or edge mode used for stitching */ - char mode; - /* handle for drawing */ - void *draw_handle; - /* island that stays in place */ - int static_island; - - /* Objects and states are aligned. */ - int objects_len; - Object **objects; - StitchState **states; - - int active_object_index; + /* clear seams of stitched edges after stitch */ + bool clear_seams; + /* use limit flag */ + bool use_limit; + /* limit to operator, same as original operator */ + float limit_dist; + /* snap uv islands together during stitching */ + bool snap_islands; + /* stitch at midpoints or at islands */ + bool midpoints; + /* vert or edge mode used for stitching */ + char mode; + /* handle for drawing */ + void *draw_handle; + /* island that stays in place */ + int static_island; + + /* Objects and states are aligned. */ + int objects_len; + Object **objects; + StitchState **states; + + int active_object_index; } StitchStateContainer; typedef struct PreviewPosition { - int data_position; - int polycount_position; + int data_position; + int polycount_position; } PreviewPosition; /* * defines for UvElement/UcEdge flags @@ -223,2529 +220,2614 @@ typedef struct PreviewPosition { #define STITCH_NO_PREVIEW -1 enum StitchModes { - STITCH_VERT, - STITCH_EDGE, + STITCH_VERT, + STITCH_EDGE, }; /* UvElement identification. */ typedef struct UvElementID { - int faceIndex; - int elementIndex; + int faceIndex; + int elementIndex; } UvElementID; /* StitchState initializition. */ typedef struct StitchStateInit { - int uv_selected_count; - UvElementID *to_select; + int uv_selected_count; + UvElementID *to_select; } StitchStateInit; /* constructor */ static StitchPreviewer *stitch_preview_init(void) { - StitchPreviewer *stitch_preview; + StitchPreviewer *stitch_preview; - stitch_preview = MEM_mallocN(sizeof(StitchPreviewer), "stitch_previewer"); - stitch_preview->preview_polys = NULL; - stitch_preview->preview_stitchable = NULL; - stitch_preview->preview_unstitchable = NULL; - stitch_preview->uvs_per_polygon = NULL; + stitch_preview = MEM_mallocN(sizeof(StitchPreviewer), "stitch_previewer"); + stitch_preview->preview_polys = NULL; + stitch_preview->preview_stitchable = NULL; + stitch_preview->preview_unstitchable = NULL; + stitch_preview->uvs_per_polygon = NULL; - stitch_preview->preview_uvs = 0; - stitch_preview->num_polys = 0; - stitch_preview->num_stitchable = 0; - stitch_preview->num_unstitchable = 0; + stitch_preview->preview_uvs = 0; + stitch_preview->num_polys = 0; + stitch_preview->num_stitchable = 0; + stitch_preview->num_unstitchable = 0; - stitch_preview->static_tris = NULL; + stitch_preview->static_tris = NULL; - stitch_preview->num_static_tris = 0; + stitch_preview->num_static_tris = 0; - return stitch_preview; + return stitch_preview; } /* destructor...yeah this should be C++ :) */ static void stitch_preview_delete(StitchPreviewer *stitch_preview) { - if (stitch_preview) { - if (stitch_preview->preview_polys) { - MEM_freeN(stitch_preview->preview_polys); - stitch_preview->preview_polys = NULL; - } - if (stitch_preview->uvs_per_polygon) { - MEM_freeN(stitch_preview->uvs_per_polygon); - stitch_preview->uvs_per_polygon = NULL; - } - if (stitch_preview->preview_stitchable) { - MEM_freeN(stitch_preview->preview_stitchable); - stitch_preview->preview_stitchable = NULL; - } - if (stitch_preview->preview_unstitchable) { - MEM_freeN(stitch_preview->preview_unstitchable); - stitch_preview->preview_unstitchable = NULL; - } - if (stitch_preview->static_tris) { - MEM_freeN(stitch_preview->static_tris); - stitch_preview->static_tris = NULL; - } - MEM_freeN(stitch_preview); - } + if (stitch_preview) { + if (stitch_preview->preview_polys) { + MEM_freeN(stitch_preview->preview_polys); + stitch_preview->preview_polys = NULL; + } + if (stitch_preview->uvs_per_polygon) { + MEM_freeN(stitch_preview->uvs_per_polygon); + stitch_preview->uvs_per_polygon = NULL; + } + if (stitch_preview->preview_stitchable) { + MEM_freeN(stitch_preview->preview_stitchable); + stitch_preview->preview_stitchable = NULL; + } + if (stitch_preview->preview_unstitchable) { + MEM_freeN(stitch_preview->preview_unstitchable); + stitch_preview->preview_unstitchable = NULL; + } + if (stitch_preview->static_tris) { + MEM_freeN(stitch_preview->static_tris); + stitch_preview->static_tris = NULL; + } + MEM_freeN(stitch_preview); + } } /* This function updates the header of the UV editor when the stitch tool updates its settings */ static void stitch_update_header(StitchStateContainer *ssc, bContext *C) { - const char *str = IFACE_( - "Mode(TAB) %s, " - "(S)nap %s, " - "(M)idpoints %s, " - "(L)imit %.2f (Alt Wheel adjust) %s, " - "Switch (I)sland, " - "shift select vertices" - ); - - char msg[UI_MAX_DRAW_STR]; - ScrArea *sa = CTX_wm_area(C); - - if (sa) { - BLI_snprintf( - msg, sizeof(msg), str, - ssc->mode == STITCH_VERT ? IFACE_("Vertex") : IFACE_("Edge"), - WM_bool_as_string(ssc->snap_islands), - WM_bool_as_string(ssc->midpoints), - ssc->limit_dist, - WM_bool_as_string(ssc->use_limit)); - - ED_workspace_status_text(C, msg); - } + const char *str = IFACE_( + "Mode(TAB) %s, " + "(S)nap %s, " + "(M)idpoints %s, " + "(L)imit %.2f (Alt Wheel adjust) %s, " + "Switch (I)sland, " + "shift select vertices"); + + char msg[UI_MAX_DRAW_STR]; + ScrArea *sa = CTX_wm_area(C); + + if (sa) { + BLI_snprintf(msg, + sizeof(msg), + str, + ssc->mode == STITCH_VERT ? IFACE_("Vertex") : IFACE_("Edge"), + WM_bool_as_string(ssc->snap_islands), + WM_bool_as_string(ssc->midpoints), + ssc->limit_dist, + WM_bool_as_string(ssc->use_limit)); + + ED_workspace_status_text(C, msg); + } } static int getNumOfIslandUvs(UvElementMap *elementMap, int island) { - if (island == elementMap->totalIslands - 1) { - return elementMap->totalUVs - elementMap->islandIndices[island]; - } - else { - return elementMap->islandIndices[island + 1] - elementMap->islandIndices[island]; - } + if (island == elementMap->totalIslands - 1) { + return elementMap->totalUVs - elementMap->islandIndices[island]; + } + else { + return elementMap->islandIndices[island + 1] - elementMap->islandIndices[island]; + } } static void stitch_uv_rotate(float mat[2][2], float medianPoint[2], float uv[2], float aspect) { - float uv_rotation_result[2]; + float uv_rotation_result[2]; - uv[1] /= aspect; + uv[1] /= aspect; - sub_v2_v2(uv, medianPoint); - mul_v2_m2v2(uv_rotation_result, mat, uv); - add_v2_v2v2(uv, uv_rotation_result, medianPoint); + sub_v2_v2(uv, medianPoint); + mul_v2_m2v2(uv_rotation_result, mat, uv); + add_v2_v2v2(uv, uv_rotation_result, medianPoint); - uv[1] *= aspect; + uv[1] *= aspect; } /* check if two uvelements are stitchable. * This should only operate on -different- separate UvElements */ -static bool stitch_check_uvs_stitchable( - UvElement *element, UvElement *element_iter, - StitchStateContainer *ssc, StitchState *state) +static bool stitch_check_uvs_stitchable(UvElement *element, + UvElement *element_iter, + StitchStateContainer *ssc, + StitchState *state) { - BMesh *bm = state->em->bm; - float limit; - - if (element_iter == element) { - return 0; - } - - limit = ssc->limit_dist; - - if (ssc->use_limit) { - MLoopUV *luv, *luv_iter; - BMLoop *l; - - - l = element->l; - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - l = element_iter->l; - luv_iter = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - - if (fabsf(luv->uv[0] - luv_iter->uv[0]) < limit && - fabsf(luv->uv[1] - luv_iter->uv[1]) < limit) - { - return 1; - } - else { - return 0; - } - } - else { - return 1; - } + BMesh *bm = state->em->bm; + float limit; + + if (element_iter == element) { + return 0; + } + + limit = ssc->limit_dist; + + if (ssc->use_limit) { + MLoopUV *luv, *luv_iter; + BMLoop *l; + + l = element->l; + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + l = element_iter->l; + luv_iter = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + + if (fabsf(luv->uv[0] - luv_iter->uv[0]) < limit && + fabsf(luv->uv[1] - luv_iter->uv[1]) < limit) { + return 1; + } + else { + return 0; + } + } + else { + return 1; + } } -static bool stitch_check_edges_stitchable( - UvEdge *edge, UvEdge *edge_iter, - StitchStateContainer *ssc, StitchState *state) +static bool stitch_check_edges_stitchable(UvEdge *edge, + UvEdge *edge_iter, + StitchStateContainer *ssc, + StitchState *state) { - BMesh *bm = state->em->bm; - float limit; - - if (edge_iter == edge) { - return 0; - } - - limit = ssc->limit_dist; - - if (ssc->use_limit) { - BMLoop *l; - MLoopUV *luv_orig1, *luv_iter1; - MLoopUV *luv_orig2, *luv_iter2; - - l = state->uvs[edge->uv1]->l; - luv_orig1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - l = state->uvs[edge_iter->uv1]->l; - luv_iter1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - - l = state->uvs[edge->uv2]->l; - luv_orig2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - l = state->uvs[edge_iter->uv2]->l; - luv_iter2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - - if (fabsf(luv_orig1->uv[0] - luv_iter1->uv[0]) < limit && - fabsf(luv_orig1->uv[1] - luv_iter1->uv[1]) < limit && - fabsf(luv_orig2->uv[0] - luv_iter2->uv[0]) < limit && - fabsf(luv_orig2->uv[1] - luv_iter2->uv[1]) < limit) - { - return 1; - } - else { - return 0; - } - } - else { - return 1; - } + BMesh *bm = state->em->bm; + float limit; + + if (edge_iter == edge) { + return 0; + } + + limit = ssc->limit_dist; + + if (ssc->use_limit) { + BMLoop *l; + MLoopUV *luv_orig1, *luv_iter1; + MLoopUV *luv_orig2, *luv_iter2; + + l = state->uvs[edge->uv1]->l; + luv_orig1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + l = state->uvs[edge_iter->uv1]->l; + luv_iter1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + + l = state->uvs[edge->uv2]->l; + luv_orig2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + l = state->uvs[edge_iter->uv2]->l; + luv_iter2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + + if (fabsf(luv_orig1->uv[0] - luv_iter1->uv[0]) < limit && + fabsf(luv_orig1->uv[1] - luv_iter1->uv[1]) < limit && + fabsf(luv_orig2->uv[0] - luv_iter2->uv[0]) < limit && + fabsf(luv_orig2->uv[1] - luv_iter2->uv[1]) < limit) { + return 1; + } + else { + return 0; + } + } + else { + return 1; + } } -static bool stitch_check_uvs_state_stitchable( - UvElement *element, UvElement *element_iter, - StitchStateContainer *ssc, StitchState *state) +static bool stitch_check_uvs_state_stitchable(UvElement *element, + UvElement *element_iter, + StitchStateContainer *ssc, + StitchState *state) { - if ((ssc->snap_islands && element->island == element_iter->island) || - (!ssc->midpoints && element->island == element_iter->island)) - { - return 0; - } + if ((ssc->snap_islands && element->island == element_iter->island) || + (!ssc->midpoints && element->island == element_iter->island)) { + return 0; + } - return stitch_check_uvs_stitchable(element, element_iter, ssc, state); + return stitch_check_uvs_stitchable(element, element_iter, ssc, state); } -static bool stitch_check_edges_state_stitchable( - UvEdge *edge, UvEdge *edge_iter, - StitchStateContainer *ssc, StitchState *state) +static bool stitch_check_edges_state_stitchable(UvEdge *edge, + UvEdge *edge_iter, + StitchStateContainer *ssc, + StitchState *state) { - if ((ssc->snap_islands && edge->element->island == edge_iter->element->island) || - (!ssc->midpoints && edge->element->island == edge_iter->element->island)) - { - return 0; - } + if ((ssc->snap_islands && edge->element->island == edge_iter->element->island) || + (!ssc->midpoints && edge->element->island == edge_iter->element->island)) { + return 0; + } - return stitch_check_edges_stitchable(edge, edge_iter, ssc, state); + return stitch_check_edges_stitchable(edge, edge_iter, ssc, state); } /* calculate snapping for islands */ -static void stitch_calculate_island_snapping( - StitchState *state, PreviewPosition *preview_position, StitchPreviewer *preview, - IslandStitchData *island_stitch_data, int final) +static void stitch_calculate_island_snapping(StitchState *state, + PreviewPosition *preview_position, + StitchPreviewer *preview, + IslandStitchData *island_stitch_data, + int final) { - BMesh *bm = state->em->bm; - int i; - UvElement *element; - - for (i = 0; i < state->element_map->totalIslands; i++) { - if (island_stitch_data[i].addedForPreview) { - int numOfIslandUVs = 0, j; - int totelem = island_stitch_data[i].num_rot_elements_neg + island_stitch_data[i].num_rot_elements; - float rotation; - float rotation_mat[2][2]; - - /* check to avoid divide by 0 */ - if (island_stitch_data[i].num_rot_elements > 1) - island_stitch_data[i].rotation /= island_stitch_data[i].num_rot_elements; - - if (island_stitch_data[i].num_rot_elements_neg > 1) - island_stitch_data[i].rotation_neg /= island_stitch_data[i].num_rot_elements_neg; - - if (island_stitch_data[i].numOfElements > 1) { - island_stitch_data[i].medianPoint[0] /= island_stitch_data[i].numOfElements; - island_stitch_data[i].medianPoint[1] /= island_stitch_data[i].numOfElements; - - island_stitch_data[i].translation[0] /= island_stitch_data[i].numOfElements; - island_stitch_data[i].translation[1] /= island_stitch_data[i].numOfElements; - } - - island_stitch_data[i].medianPoint[1] /= state->aspect; - if ((island_stitch_data[i].rotation + island_stitch_data[i].rotation_neg < (float)M_PI_2) || - island_stitch_data[i].num_rot_elements == 0 || island_stitch_data[i].num_rot_elements_neg == 0) - { - rotation = (island_stitch_data[i].rotation * island_stitch_data[i].num_rot_elements - - island_stitch_data[i].rotation_neg * - island_stitch_data[i].num_rot_elements_neg) / totelem; - } - else { - rotation = (island_stitch_data[i].rotation * island_stitch_data[i].num_rot_elements + - (2.0f * (float)M_PI - island_stitch_data[i].rotation_neg) * - island_stitch_data[i].num_rot_elements_neg) / totelem; - } - - angle_to_mat2(rotation_mat, rotation); - numOfIslandUVs = getNumOfIslandUvs(state->element_map, i); - element = &state->element_map->buf[state->element_map->islandIndices[i]]; - for (j = 0; j < numOfIslandUVs; j++, element++) { - /* stitchable uvs have already been processed, don't process */ - if (!(element->flag & STITCH_PROCESSED)) { - MLoopUV *luv; - BMLoop *l; - - l = element->l; - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - - if (final) { - - stitch_uv_rotate(rotation_mat, island_stitch_data[i].medianPoint, luv->uv, state->aspect); - - add_v2_v2(luv->uv, island_stitch_data[i].translation); - } - - else { - - int face_preview_pos = preview_position[BM_elem_index_get(element->l->f)].data_position; - - stitch_uv_rotate(rotation_mat, island_stitch_data[i].medianPoint, - preview->preview_polys + face_preview_pos + 2 * element->loop_of_poly_index, - state->aspect); - - add_v2_v2(preview->preview_polys + face_preview_pos + 2 * element->loop_of_poly_index, - island_stitch_data[i].translation); - } - } - /* cleanup */ - element->flag &= STITCH_SELECTED; - } - } - } + BMesh *bm = state->em->bm; + int i; + UvElement *element; + + for (i = 0; i < state->element_map->totalIslands; i++) { + if (island_stitch_data[i].addedForPreview) { + int numOfIslandUVs = 0, j; + int totelem = island_stitch_data[i].num_rot_elements_neg + + island_stitch_data[i].num_rot_elements; + float rotation; + float rotation_mat[2][2]; + + /* check to avoid divide by 0 */ + if (island_stitch_data[i].num_rot_elements > 1) + island_stitch_data[i].rotation /= island_stitch_data[i].num_rot_elements; + + if (island_stitch_data[i].num_rot_elements_neg > 1) + island_stitch_data[i].rotation_neg /= island_stitch_data[i].num_rot_elements_neg; + + if (island_stitch_data[i].numOfElements > 1) { + island_stitch_data[i].medianPoint[0] /= island_stitch_data[i].numOfElements; + island_stitch_data[i].medianPoint[1] /= island_stitch_data[i].numOfElements; + + island_stitch_data[i].translation[0] /= island_stitch_data[i].numOfElements; + island_stitch_data[i].translation[1] /= island_stitch_data[i].numOfElements; + } + + island_stitch_data[i].medianPoint[1] /= state->aspect; + if ((island_stitch_data[i].rotation + island_stitch_data[i].rotation_neg < (float)M_PI_2) || + island_stitch_data[i].num_rot_elements == 0 || + island_stitch_data[i].num_rot_elements_neg == 0) { + rotation = (island_stitch_data[i].rotation * island_stitch_data[i].num_rot_elements - + island_stitch_data[i].rotation_neg * + island_stitch_data[i].num_rot_elements_neg) / + totelem; + } + else { + rotation = (island_stitch_data[i].rotation * island_stitch_data[i].num_rot_elements + + (2.0f * (float)M_PI - island_stitch_data[i].rotation_neg) * + island_stitch_data[i].num_rot_elements_neg) / + totelem; + } + + angle_to_mat2(rotation_mat, rotation); + numOfIslandUVs = getNumOfIslandUvs(state->element_map, i); + element = &state->element_map->buf[state->element_map->islandIndices[i]]; + for (j = 0; j < numOfIslandUVs; j++, element++) { + /* stitchable uvs have already been processed, don't process */ + if (!(element->flag & STITCH_PROCESSED)) { + MLoopUV *luv; + BMLoop *l; + + l = element->l; + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + + if (final) { + + stitch_uv_rotate( + rotation_mat, island_stitch_data[i].medianPoint, luv->uv, state->aspect); + + add_v2_v2(luv->uv, island_stitch_data[i].translation); + } + + else { + + int face_preview_pos = + preview_position[BM_elem_index_get(element->l->f)].data_position; + + stitch_uv_rotate(rotation_mat, + island_stitch_data[i].medianPoint, + preview->preview_polys + face_preview_pos + + 2 * element->loop_of_poly_index, + state->aspect); + + add_v2_v2(preview->preview_polys + face_preview_pos + 2 * element->loop_of_poly_index, + island_stitch_data[i].translation); + } + } + /* cleanup */ + element->flag &= STITCH_SELECTED; + } + } + } } - - -static void stitch_island_calculate_edge_rotation( - UvEdge *edge, StitchStateContainer *ssc, StitchState *state, UVVertAverage *uv_average, - unsigned int *uvfinal_map, IslandStitchData *island_stitch_data) +static void stitch_island_calculate_edge_rotation(UvEdge *edge, + StitchStateContainer *ssc, + StitchState *state, + UVVertAverage *uv_average, + unsigned int *uvfinal_map, + IslandStitchData *island_stitch_data) { - BMesh *bm = state->em->bm; - UvElement *element1, *element2; - float uv1[2], uv2[2]; - float edgecos, edgesin; - int index1, index2; - float rotation; - MLoopUV *luv1, *luv2; - - element1 = state->uvs[edge->uv1]; - element2 = state->uvs[edge->uv2]; - - luv1 = CustomData_bmesh_get(&bm->ldata, element1->l->head.data, CD_MLOOPUV); - luv2 = CustomData_bmesh_get(&bm->ldata, element2->l->head.data, CD_MLOOPUV); - - if (ssc->mode == STITCH_VERT) { - index1 = uvfinal_map[element1 - state->element_map->buf]; - index2 = uvfinal_map[element2 - state->element_map->buf]; - } - else { - index1 = edge->uv1; - index2 = edge->uv2; - } - /* the idea here is to take the directions of the edges and find the rotation between - * final and initial direction. This, using inner and outer vector products, - * gives the angle. Directions are differences so... */ - uv1[0] = luv2->uv[0] - luv1->uv[0]; - uv1[1] = luv2->uv[1] - luv1->uv[1]; - - uv1[1] /= state->aspect; - - uv2[0] = uv_average[index2].uv[0] - uv_average[index1].uv[0]; - uv2[1] = uv_average[index2].uv[1] - uv_average[index1].uv[1]; - - uv2[1] /= state->aspect; - - normalize_v2(uv1); - normalize_v2(uv2); - - edgecos = dot_v2v2(uv1, uv2); - edgesin = cross_v2v2(uv1, uv2); - rotation = acosf(max_ff(-1.0f, min_ff(1.0f, edgecos))); - - if (edgesin > 0.0f) { - island_stitch_data[element1->island].num_rot_elements++; - island_stitch_data[element1->island].rotation += rotation; - } - else { - island_stitch_data[element1->island].num_rot_elements_neg++; - island_stitch_data[element1->island].rotation_neg += rotation; - } + BMesh *bm = state->em->bm; + UvElement *element1, *element2; + float uv1[2], uv2[2]; + float edgecos, edgesin; + int index1, index2; + float rotation; + MLoopUV *luv1, *luv2; + + element1 = state->uvs[edge->uv1]; + element2 = state->uvs[edge->uv2]; + + luv1 = CustomData_bmesh_get(&bm->ldata, element1->l->head.data, CD_MLOOPUV); + luv2 = CustomData_bmesh_get(&bm->ldata, element2->l->head.data, CD_MLOOPUV); + + if (ssc->mode == STITCH_VERT) { + index1 = uvfinal_map[element1 - state->element_map->buf]; + index2 = uvfinal_map[element2 - state->element_map->buf]; + } + else { + index1 = edge->uv1; + index2 = edge->uv2; + } + /* the idea here is to take the directions of the edges and find the rotation between + * final and initial direction. This, using inner and outer vector products, + * gives the angle. Directions are differences so... */ + uv1[0] = luv2->uv[0] - luv1->uv[0]; + uv1[1] = luv2->uv[1] - luv1->uv[1]; + + uv1[1] /= state->aspect; + + uv2[0] = uv_average[index2].uv[0] - uv_average[index1].uv[0]; + uv2[1] = uv_average[index2].uv[1] - uv_average[index1].uv[1]; + + uv2[1] /= state->aspect; + + normalize_v2(uv1); + normalize_v2(uv2); + + edgecos = dot_v2v2(uv1, uv2); + edgesin = cross_v2v2(uv1, uv2); + rotation = acosf(max_ff(-1.0f, min_ff(1.0f, edgecos))); + + if (edgesin > 0.0f) { + island_stitch_data[element1->island].num_rot_elements++; + island_stitch_data[element1->island].rotation += rotation; + } + else { + island_stitch_data[element1->island].num_rot_elements_neg++; + island_stitch_data[element1->island].rotation_neg += rotation; + } } - -static void stitch_island_calculate_vert_rotation( - UvElement *element, StitchStateContainer *ssc, StitchState *state, - IslandStitchData *island_stitch_data) +static void stitch_island_calculate_vert_rotation(UvElement *element, + StitchStateContainer *ssc, + StitchState *state, + IslandStitchData *island_stitch_data) { - float edgecos = 1.0f, edgesin = 0.0f; - int index; - UvElement *element_iter; - float rotation = 0, rotation_neg = 0; - int rot_elem = 0, rot_elem_neg = 0; - BMLoop *l; - - if (element->island == ssc->static_island && !ssc->midpoints) - return; - - l = element->l; - - index = BM_elem_index_get(l->v); - - element_iter = state->element_map->vert[index]; - - for (; element_iter; element_iter = element_iter->next) { - if (element_iter->separate && stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) { - int index_tmp1, index_tmp2; - float normal[2]; - - /* only calculate rotation against static island uv verts */ - if (!ssc->midpoints && element_iter->island != ssc->static_island) - continue; - - index_tmp1 = element_iter - state->element_map->buf; - index_tmp1 = state->map[index_tmp1]; - index_tmp2 = element - state->element_map->buf; - index_tmp2 = state->map[index_tmp2]; - - negate_v2_v2(normal, state->normals + index_tmp2 * 2); - edgecos = dot_v2v2(normal, state->normals + index_tmp1 * 2); - edgesin = cross_v2v2(normal, state->normals + index_tmp1 * 2); - if (edgesin > 0.0f) { - rotation += acosf(max_ff(-1.0f, min_ff(1.0f, edgecos))); - rot_elem++; - } - else { - rotation_neg += acosf(max_ff(-1.0f, min_ff(1.0f, edgecos))); - rot_elem_neg++; - } - } - } - - if (ssc->midpoints) { - rotation /= 2.0f; - rotation_neg /= 2.0f; - } - island_stitch_data[element->island].num_rot_elements += rot_elem; - island_stitch_data[element->island].rotation += rotation; - island_stitch_data[element->island].num_rot_elements_neg += rot_elem_neg; - island_stitch_data[element->island].rotation_neg += rotation_neg; + float edgecos = 1.0f, edgesin = 0.0f; + int index; + UvElement *element_iter; + float rotation = 0, rotation_neg = 0; + int rot_elem = 0, rot_elem_neg = 0; + BMLoop *l; + + if (element->island == ssc->static_island && !ssc->midpoints) + return; + + l = element->l; + + index = BM_elem_index_get(l->v); + + element_iter = state->element_map->vert[index]; + + for (; element_iter; element_iter = element_iter->next) { + if (element_iter->separate && + stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) { + int index_tmp1, index_tmp2; + float normal[2]; + + /* only calculate rotation against static island uv verts */ + if (!ssc->midpoints && element_iter->island != ssc->static_island) + continue; + + index_tmp1 = element_iter - state->element_map->buf; + index_tmp1 = state->map[index_tmp1]; + index_tmp2 = element - state->element_map->buf; + index_tmp2 = state->map[index_tmp2]; + + negate_v2_v2(normal, state->normals + index_tmp2 * 2); + edgecos = dot_v2v2(normal, state->normals + index_tmp1 * 2); + edgesin = cross_v2v2(normal, state->normals + index_tmp1 * 2); + if (edgesin > 0.0f) { + rotation += acosf(max_ff(-1.0f, min_ff(1.0f, edgecos))); + rot_elem++; + } + else { + rotation_neg += acosf(max_ff(-1.0f, min_ff(1.0f, edgecos))); + rot_elem_neg++; + } + } + } + + if (ssc->midpoints) { + rotation /= 2.0f; + rotation_neg /= 2.0f; + } + island_stitch_data[element->island].num_rot_elements += rot_elem; + island_stitch_data[element->island].rotation += rotation; + island_stitch_data[element->island].num_rot_elements_neg += rot_elem_neg; + island_stitch_data[element->island].rotation_neg += rotation_neg; } - static void state_delete(StitchState *state) { - if (state) { - if (state->island_is_stitchable) { - MEM_freeN(state->island_is_stitchable); - } - if (state->element_map) { - BM_uv_element_map_free(state->element_map); - } - if (state->uvs) { - MEM_freeN(state->uvs); - } - if (state->selection_stack) { - MEM_freeN(state->selection_stack); - } - if (state->tris_per_island) { - MEM_freeN(state->tris_per_island); - } - if (state->map) { - MEM_freeN(state->map); - } - if (state->normals) { - MEM_freeN(state->normals); - } - if (state->edges) { - MEM_freeN(state->edges); - } - if (state->stitch_preview) { - stitch_preview_delete(state->stitch_preview); - } - if (state->edge_hash) { - BLI_ghash_free(state->edge_hash, NULL, NULL); - } - MEM_freeN(state); - } + if (state) { + if (state->island_is_stitchable) { + MEM_freeN(state->island_is_stitchable); + } + if (state->element_map) { + BM_uv_element_map_free(state->element_map); + } + if (state->uvs) { + MEM_freeN(state->uvs); + } + if (state->selection_stack) { + MEM_freeN(state->selection_stack); + } + if (state->tris_per_island) { + MEM_freeN(state->tris_per_island); + } + if (state->map) { + MEM_freeN(state->map); + } + if (state->normals) { + MEM_freeN(state->normals); + } + if (state->edges) { + MEM_freeN(state->edges); + } + if (state->stitch_preview) { + stitch_preview_delete(state->stitch_preview); + } + if (state->edge_hash) { + BLI_ghash_free(state->edge_hash, NULL, NULL); + } + MEM_freeN(state); + } } static void state_delete_all(StitchStateContainer *ssc) { - if (ssc) { - for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { - state_delete(ssc->states[ob_index]); - } - MEM_freeN(ssc->states); - MEM_freeN(ssc->objects); - MEM_freeN(ssc); - } + if (ssc) { + for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { + state_delete(ssc->states[ob_index]); + } + MEM_freeN(ssc->states); + MEM_freeN(ssc->objects); + MEM_freeN(ssc); + } } static void stitch_uv_edge_generate_linked_edges(GHash *edge_hash, StitchState *state) { - UvEdge *edges = state->edges; - const int *map = state->map; - UvElementMap *element_map = state->element_map; - UvElement *first_element = element_map->buf; - int i; - - for (i = 0; i < state->total_separate_edges; i++) { - UvEdge *edge = edges + i; - - if (edge->first) - continue; - - /* only boundary edges can be stitched. Yes. Sorry about that :p */ - if (edge->flag & STITCH_BOUNDARY) { - UvElement *element1 = state->uvs[edge->uv1]; - UvElement *element2 = state->uvs[edge->uv2]; - - /* Now iterate through all faces and try to find edges sharing the same vertices */ - UvElement *iter1 = element_map->vert[BM_elem_index_get(element1->l->v)]; - UvEdge *last_set = edge; - int elemindex2 = BM_elem_index_get(element2->l->v); - - edge->first = edge; - - for (; iter1; iter1 = iter1->next) { - UvElement *iter2 = NULL; - - /* check to see if other vertex of edge belongs to same vertex as */ - if (BM_elem_index_get(iter1->l->next->v) == elemindex2) - iter2 = BM_uv_element_get(element_map, iter1->l->f, iter1->l->next); - else if (BM_elem_index_get(iter1->l->prev->v) == elemindex2) - iter2 = BM_uv_element_get(element_map, iter1->l->f, iter1->l->prev); - - if (iter2) { - int index1 = map[iter1 - first_element]; - int index2 = map[iter2 - first_element]; - UvEdge edgetmp; - UvEdge *edge2, *eiter; - bool valid = true; - - /* make sure the indices are well behaved */ - if (index1 > index2) { - SWAP(int, index1, index2); - } - - edgetmp.uv1 = index1; - edgetmp.uv2 = index2; - - /* get the edge from the hash */ - edge2 = BLI_ghash_lookup(edge_hash, &edgetmp); - - /* more iteration to make sure non-manifold case is handled nicely */ - for (eiter = edge; eiter; eiter = eiter->next) { - if (edge2 == eiter) { - valid = false; - break; - } - } - - if (valid) { - /* here I am taking care of non manifold case, assuming more than two matching edges. - * I am not too sure we want this though */ - last_set->next = edge2; - last_set = edge2; - /* set first, similarly to uv elements. - * Now we can iterate among common edges easily */ - edge2->first = edge; - } - } - } - } - else { - /* so stitchability code works */ - edge->first = edge; - } - } + UvEdge *edges = state->edges; + const int *map = state->map; + UvElementMap *element_map = state->element_map; + UvElement *first_element = element_map->buf; + int i; + + for (i = 0; i < state->total_separate_edges; i++) { + UvEdge *edge = edges + i; + + if (edge->first) + continue; + + /* only boundary edges can be stitched. Yes. Sorry about that :p */ + if (edge->flag & STITCH_BOUNDARY) { + UvElement *element1 = state->uvs[edge->uv1]; + UvElement *element2 = state->uvs[edge->uv2]; + + /* Now iterate through all faces and try to find edges sharing the same vertices */ + UvElement *iter1 = element_map->vert[BM_elem_index_get(element1->l->v)]; + UvEdge *last_set = edge; + int elemindex2 = BM_elem_index_get(element2->l->v); + + edge->first = edge; + + for (; iter1; iter1 = iter1->next) { + UvElement *iter2 = NULL; + + /* check to see if other vertex of edge belongs to same vertex as */ + if (BM_elem_index_get(iter1->l->next->v) == elemindex2) + iter2 = BM_uv_element_get(element_map, iter1->l->f, iter1->l->next); + else if (BM_elem_index_get(iter1->l->prev->v) == elemindex2) + iter2 = BM_uv_element_get(element_map, iter1->l->f, iter1->l->prev); + + if (iter2) { + int index1 = map[iter1 - first_element]; + int index2 = map[iter2 - first_element]; + UvEdge edgetmp; + UvEdge *edge2, *eiter; + bool valid = true; + + /* make sure the indices are well behaved */ + if (index1 > index2) { + SWAP(int, index1, index2); + } + + edgetmp.uv1 = index1; + edgetmp.uv2 = index2; + + /* get the edge from the hash */ + edge2 = BLI_ghash_lookup(edge_hash, &edgetmp); + + /* more iteration to make sure non-manifold case is handled nicely */ + for (eiter = edge; eiter; eiter = eiter->next) { + if (edge2 == eiter) { + valid = false; + break; + } + } + + if (valid) { + /* here I am taking care of non manifold case, assuming more than two matching edges. + * I am not too sure we want this though */ + last_set->next = edge2; + last_set = edge2; + /* set first, similarly to uv elements. + * Now we can iterate among common edges easily */ + edge2->first = edge; + } + } + } + } + else { + /* so stitchability code works */ + edge->first = edge; + } + } } - /* checks for remote uvs that may be stitched with a certain uv, flags them if stitchable. */ -static void determine_uv_stitchability( - UvElement *element, StitchStateContainer *ssc, StitchState *state, - IslandStitchData *island_stitch_data) +static void determine_uv_stitchability(UvElement *element, + StitchStateContainer *ssc, + StitchState *state, + IslandStitchData *island_stitch_data) { - int vert_index; - UvElement *element_iter; - BMLoop *l; - - l = element->l; - - vert_index = BM_elem_index_get(l->v); - element_iter = state->element_map->vert[vert_index]; - - for (; element_iter; element_iter = element_iter->next) { - if (element_iter->separate) { - if (stitch_check_uvs_stitchable(element, element_iter, ssc, state)) { - island_stitch_data[element_iter->island].stitchableCandidate = 1; - island_stitch_data[element->island].stitchableCandidate = 1; - element->flag |= STITCH_STITCHABLE_CANDIDATE; - } - } - } + int vert_index; + UvElement *element_iter; + BMLoop *l; + + l = element->l; + + vert_index = BM_elem_index_get(l->v); + element_iter = state->element_map->vert[vert_index]; + + for (; element_iter; element_iter = element_iter->next) { + if (element_iter->separate) { + if (stitch_check_uvs_stitchable(element, element_iter, ssc, state)) { + island_stitch_data[element_iter->island].stitchableCandidate = 1; + island_stitch_data[element->island].stitchableCandidate = 1; + element->flag |= STITCH_STITCHABLE_CANDIDATE; + } + } + } } -static void determine_uv_edge_stitchability( - UvEdge *edge, StitchStateContainer *ssc, StitchState *state, - IslandStitchData *island_stitch_data) +static void determine_uv_edge_stitchability(UvEdge *edge, + StitchStateContainer *ssc, + StitchState *state, + IslandStitchData *island_stitch_data) { - UvEdge *edge_iter = edge->first; - - for (; edge_iter; edge_iter = edge_iter->next) { - if (stitch_check_edges_stitchable(edge, edge_iter, ssc, state)) { - island_stitch_data[edge_iter->element->island].stitchableCandidate = 1; - island_stitch_data[edge->element->island].stitchableCandidate = 1; - edge->flag |= STITCH_STITCHABLE_CANDIDATE; - } - } + UvEdge *edge_iter = edge->first; + + for (; edge_iter; edge_iter = edge_iter->next) { + if (stitch_check_edges_stitchable(edge, edge_iter, ssc, state)) { + island_stitch_data[edge_iter->element->island].stitchableCandidate = 1; + island_stitch_data[edge->element->island].stitchableCandidate = 1; + edge->flag |= STITCH_STITCHABLE_CANDIDATE; + } + } } - /* set preview buffer position of UV face in editface->tmp.l */ -static void stitch_set_face_preview_buffer_position( - BMFace *efa, StitchPreviewer *preview, PreviewPosition *preview_position) +static void stitch_set_face_preview_buffer_position(BMFace *efa, + StitchPreviewer *preview, + PreviewPosition *preview_position) { - int index = BM_elem_index_get(efa); + int index = BM_elem_index_get(efa); - if (preview_position[index].data_position == STITCH_NO_PREVIEW) { - preview_position[index].data_position = preview->preview_uvs * 2; - preview_position[index].polycount_position = preview->num_polys++; - preview->preview_uvs += efa->len; - } + if (preview_position[index].data_position == STITCH_NO_PREVIEW) { + preview_position[index].data_position = preview->preview_uvs * 2; + preview_position[index].polycount_position = preview->num_polys++; + preview->preview_uvs += efa->len; + } } - /* setup face preview for all coincident uvs and their faces */ -static void stitch_setup_face_preview_for_uv_group( - UvElement *element, StitchStateContainer *ssc, StitchState *state, - IslandStitchData *island_stitch_data, PreviewPosition *preview_position) +static void stitch_setup_face_preview_for_uv_group(UvElement *element, + StitchStateContainer *ssc, + StitchState *state, + IslandStitchData *island_stitch_data, + PreviewPosition *preview_position) { - StitchPreviewer *preview = state->stitch_preview; + StitchPreviewer *preview = state->stitch_preview; - /* static island does not change so returning immediately */ - if (ssc->snap_islands && !ssc->midpoints && ssc->static_island == element->island) - return; + /* static island does not change so returning immediately */ + if (ssc->snap_islands && !ssc->midpoints && ssc->static_island == element->island) + return; - if (ssc->snap_islands) { - island_stitch_data[element->island].addedForPreview = 1; - } + if (ssc->snap_islands) { + island_stitch_data[element->island].addedForPreview = 1; + } - do { - stitch_set_face_preview_buffer_position(element->l->f, preview, preview_position); - element = element->next; - } while (element && !element->separate); + do { + stitch_set_face_preview_buffer_position(element->l->f, preview, preview_position); + element = element->next; + } while (element && !element->separate); } - /* checks if uvs are indeed stitchable and registers so that they can be shown in preview */ -static void stitch_validate_uv_stitchability( - UvElement *element, StitchStateContainer *ssc, StitchState *state, - IslandStitchData *island_stitch_data, PreviewPosition *preview_position) +static void stitch_validate_uv_stitchability(UvElement *element, + StitchStateContainer *ssc, + StitchState *state, + IslandStitchData *island_stitch_data, + PreviewPosition *preview_position) { - StitchPreviewer *preview = state->stitch_preview; - - /* If not the active object, then it's unstitchable */ - if (ssc->states[ssc->active_object_index] != state) { - preview->num_unstitchable++; - return; - } - - UvElement *element_iter; - int vert_index; - BMLoop *l; - - l = element->l; - - vert_index = BM_elem_index_get(l->v); - - element_iter = state->element_map->vert[vert_index]; - - for (; element_iter; element_iter = element_iter->next) { - if (element_iter->separate) { - if (element_iter == element) - continue; - if (stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) { - if ((element_iter->island == ssc->static_island) || (element->island == ssc->static_island)) { - element->flag |= STITCH_STITCHABLE; - preview->num_stitchable++; - stitch_setup_face_preview_for_uv_group(element, ssc, state, island_stitch_data, preview_position); - return; - } - } - } - } - - /* this can happen if the uvs to be stitched are not on a stitchable island */ - if (!(element->flag & STITCH_STITCHABLE)) { - preview->num_unstitchable++; - } + StitchPreviewer *preview = state->stitch_preview; + + /* If not the active object, then it's unstitchable */ + if (ssc->states[ssc->active_object_index] != state) { + preview->num_unstitchable++; + return; + } + + UvElement *element_iter; + int vert_index; + BMLoop *l; + + l = element->l; + + vert_index = BM_elem_index_get(l->v); + + element_iter = state->element_map->vert[vert_index]; + + for (; element_iter; element_iter = element_iter->next) { + if (element_iter->separate) { + if (element_iter == element) + continue; + if (stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) { + if ((element_iter->island == ssc->static_island) || + (element->island == ssc->static_island)) { + element->flag |= STITCH_STITCHABLE; + preview->num_stitchable++; + stitch_setup_face_preview_for_uv_group( + element, ssc, state, island_stitch_data, preview_position); + return; + } + } + } + } + + /* this can happen if the uvs to be stitched are not on a stitchable island */ + if (!(element->flag & STITCH_STITCHABLE)) { + preview->num_unstitchable++; + } } - -static void stitch_validate_edge_stitchability( - UvEdge *edge, StitchStateContainer *ssc, StitchState *state, - IslandStitchData *island_stitch_data, PreviewPosition *preview_position) +static void stitch_validate_edge_stitchability(UvEdge *edge, + StitchStateContainer *ssc, + StitchState *state, + IslandStitchData *island_stitch_data, + PreviewPosition *preview_position) { - StitchPreviewer *preview = state->stitch_preview; - - /* If not the active object, then it's unstitchable */ - if (ssc->states[ssc->active_object_index] != state) { - preview->num_unstitchable++; - return; - } - - UvEdge *edge_iter = edge->first; - - for (; edge_iter; edge_iter = edge_iter->next) { - if (edge_iter == edge) - continue; - if (stitch_check_edges_state_stitchable(edge, edge_iter, ssc, state)) { - if ((edge_iter->element->island == ssc->static_island) || (edge->element->island == ssc->static_island)) { - edge->flag |= STITCH_STITCHABLE; - preview->num_stitchable++; - stitch_setup_face_preview_for_uv_group(state->uvs[edge->uv1], - ssc, - state, - island_stitch_data, - preview_position); - stitch_setup_face_preview_for_uv_group(state->uvs[edge->uv2], - ssc, - state, - island_stitch_data, - preview_position); - return; - } - } - } - - /* this can happen if the uvs to be stitched are not on a stitchable island */ - if (!(edge->flag & STITCH_STITCHABLE)) { - preview->num_unstitchable++; - } + StitchPreviewer *preview = state->stitch_preview; + + /* If not the active object, then it's unstitchable */ + if (ssc->states[ssc->active_object_index] != state) { + preview->num_unstitchable++; + return; + } + + UvEdge *edge_iter = edge->first; + + for (; edge_iter; edge_iter = edge_iter->next) { + if (edge_iter == edge) + continue; + if (stitch_check_edges_state_stitchable(edge, edge_iter, ssc, state)) { + if ((edge_iter->element->island == ssc->static_island) || + (edge->element->island == ssc->static_island)) { + edge->flag |= STITCH_STITCHABLE; + preview->num_stitchable++; + stitch_setup_face_preview_for_uv_group( + state->uvs[edge->uv1], ssc, state, island_stitch_data, preview_position); + stitch_setup_face_preview_for_uv_group( + state->uvs[edge->uv2], ssc, state, island_stitch_data, preview_position); + return; + } + } + } + + /* this can happen if the uvs to be stitched are not on a stitchable island */ + if (!(edge->flag & STITCH_STITCHABLE)) { + preview->num_unstitchable++; + } } - -static void stitch_propagate_uv_final_position( - Scene *scene, - UvElement *element, int index, PreviewPosition *preview_position, - UVVertAverage *final_position, StitchStateContainer *ssc, StitchState *state, - const bool final) +static void stitch_propagate_uv_final_position(Scene *scene, + UvElement *element, + int index, + PreviewPosition *preview_position, + UVVertAverage *final_position, + StitchStateContainer *ssc, + StitchState *state, + const bool final) { - BMesh *bm = state->em->bm; - StitchPreviewer *preview = state->stitch_preview; - - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - - if (element->flag & STITCH_STITCHABLE) { - UvElement *element_iter = element; - /* propagate to coincident uvs */ - do { - BMLoop *l; - MLoopUV *luv; - - l = element_iter->l; - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - - element_iter->flag |= STITCH_PROCESSED; - /* either flush to preview or to the MTFace, if final */ - if (final) { - copy_v2_v2(luv->uv, final_position[index].uv); - - uvedit_uv_select_enable(state->em, scene, l, false, cd_loop_uv_offset); - } - else { - int face_preview_pos = preview_position[BM_elem_index_get(element_iter->l->f)].data_position; - if (face_preview_pos != STITCH_NO_PREVIEW) { - copy_v2_v2(preview->preview_polys + face_preview_pos + 2 * element_iter->loop_of_poly_index, - final_position[index].uv); - } - } - - /* end of calculations, keep only the selection flag */ - if ((!ssc->snap_islands) || ((!ssc->midpoints) && (element_iter->island == ssc->static_island))) { - element_iter->flag &= STITCH_SELECTED; - } - - element_iter = element_iter->next; - } while (element_iter && !element_iter->separate); - } + BMesh *bm = state->em->bm; + StitchPreviewer *preview = state->stitch_preview; + + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + + if (element->flag & STITCH_STITCHABLE) { + UvElement *element_iter = element; + /* propagate to coincident uvs */ + do { + BMLoop *l; + MLoopUV *luv; + + l = element_iter->l; + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + + element_iter->flag |= STITCH_PROCESSED; + /* either flush to preview or to the MTFace, if final */ + if (final) { + copy_v2_v2(luv->uv, final_position[index].uv); + + uvedit_uv_select_enable(state->em, scene, l, false, cd_loop_uv_offset); + } + else { + int face_preview_pos = + preview_position[BM_elem_index_get(element_iter->l->f)].data_position; + if (face_preview_pos != STITCH_NO_PREVIEW) { + copy_v2_v2(preview->preview_polys + face_preview_pos + + 2 * element_iter->loop_of_poly_index, + final_position[index].uv); + } + } + + /* end of calculations, keep only the selection flag */ + if ((!ssc->snap_islands) || + ((!ssc->midpoints) && (element_iter->island == ssc->static_island))) { + element_iter->flag &= STITCH_SELECTED; + } + + element_iter = element_iter->next; + } while (element_iter && !element_iter->separate); + } } /* main processing function. It calculates preview and final positions. */ -static int stitch_process_data( - StitchStateContainer *ssc, StitchState *state, Scene *scene, int final) +static int stitch_process_data(StitchStateContainer *ssc, + StitchState *state, + Scene *scene, + int final) { - int i; - StitchPreviewer *preview; - IslandStitchData *island_stitch_data = NULL; - int previous_island = ssc->static_island; - BMesh *bm = state->em->bm; - BMFace *efa; - BMIter iter; - UVVertAverage *final_position = NULL; - bool is_active_state = (state == ssc->states[ssc->active_object_index]); - - char stitch_midpoints = ssc->midpoints; - /* used to map uv indices to uvaverage indices for selection */ - unsigned int *uvfinal_map = NULL; - /* per face preview position in preview buffer */ - PreviewPosition *preview_position = NULL; - - /* cleanup previous preview */ - stitch_preview_delete(state->stitch_preview); - preview = state->stitch_preview = stitch_preview_init(); - if (preview == NULL) - return 0; - - preview_position = MEM_mallocN(bm->totface * sizeof(*preview_position), "stitch_face_preview_position"); - /* each face holds its position in the preview buffer in tmp. -1 is uninitialized */ - for (i = 0; i < bm->totface; i++) { - preview_position[i].data_position = STITCH_NO_PREVIEW; - } - - island_stitch_data = MEM_callocN(sizeof(*island_stitch_data) * state->element_map->totalIslands, - "stitch_island_data"); - if (!island_stitch_data) { - return 0; - } - - /* store indices to editVerts and Faces. May be unneeded but ensuring anyway */ - BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE); - - /**************************************** - * First determine stitchability of uvs * - ****************************************/ - - for (i = 0; i < state->selection_size; i++) { - if (ssc->mode == STITCH_VERT) { - UvElement *element = (UvElement *)state->selection_stack[i]; - determine_uv_stitchability(element, ssc, state, island_stitch_data); - } - else { - UvEdge *edge = (UvEdge *)state->selection_stack[i]; - determine_uv_edge_stitchability(edge, ssc, state, island_stitch_data); - } - } - - /* remember stitchable candidates as places the 'I' button */ - /* will stop at. */ - for (int island_idx = 0; island_idx < state->element_map->totalIslands; island_idx++) { - state->island_is_stitchable[island_idx] = island_stitch_data[island_idx].stitchableCandidate ? true : false; - } - - if (is_active_state) { - /* set static island to one that is added for preview */ - ssc->static_island %= state->element_map->totalIslands; - while (!(island_stitch_data[ssc->static_island].stitchableCandidate)) { - ssc->static_island++; - ssc->static_island %= state->element_map->totalIslands; - /* this is entirely possible if for example limit stitching - * with no stitchable verts or no selection */ - if (ssc->static_island == previous_island) { - break; - } - } - } - - for (i = 0; i < state->selection_size; i++) { - if (ssc->mode == STITCH_VERT) { - UvElement *element = (UvElement *)state->selection_stack[i]; - if (element->flag & STITCH_STITCHABLE_CANDIDATE) { - element->flag &= ~STITCH_STITCHABLE_CANDIDATE; - stitch_validate_uv_stitchability(element, ssc, state, island_stitch_data, preview_position); - } - else { - /* add to preview for unstitchable */ - preview->num_unstitchable++; - } - } - else { - UvEdge *edge = (UvEdge *)state->selection_stack[i]; - if (edge->flag & STITCH_STITCHABLE_CANDIDATE) { - edge->flag &= ~STITCH_STITCHABLE_CANDIDATE; - stitch_validate_edge_stitchability(edge, ssc, state, island_stitch_data, preview_position); - } - else { - preview->num_unstitchable++; - } - } - } - - /********************************************************************* - * Setup the stitchable & unstitchable preview buffers and fill * - * them with the appropriate data * - *********************************************************************/ - if (!final) { - BMLoop *l; - MLoopUV *luv; - int stitchBufferIndex = 0, unstitchBufferIndex = 0; - int preview_size = (ssc->mode == STITCH_VERT) ? 2 : 4; - /* initialize the preview buffers */ - preview->preview_stitchable = (float *)MEM_mallocN(preview->num_stitchable * sizeof(float) * preview_size, - "stitch_preview_stitchable_data"); - preview->preview_unstitchable = (float *)MEM_mallocN(preview->num_unstitchable * sizeof(float) * preview_size, - "stitch_preview_unstitchable_data"); - - /* will cause cancel and freeing of all data structures so OK */ - if (!preview->preview_stitchable || !preview->preview_unstitchable) { - return 0; - } - - /* fill the appropriate preview buffers */ - if (ssc->mode == STITCH_VERT) { - for (i = 0; i < state->total_separate_uvs; i++) { - UvElement *element = (UvElement *)state->uvs[i]; - if (element->flag & STITCH_STITCHABLE) { - l = element->l; - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - - copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 2], luv->uv); - - stitchBufferIndex++; - } - else if (element->flag & STITCH_SELECTED) { - l = element->l; - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - - copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 2], luv->uv); - unstitchBufferIndex++; - } - } - } - else { - for (i = 0; i < state->total_separate_edges; i++) { - UvEdge *edge = state->edges + i; - UvElement *element1 = state->uvs[edge->uv1]; - UvElement *element2 = state->uvs[edge->uv2]; - - if (edge->flag & STITCH_STITCHABLE) { - l = element1->l; - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 4], luv->uv); - - l = element2->l; - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 4 + 2], luv->uv); - - stitchBufferIndex++; - BLI_assert(stitchBufferIndex <= preview->num_stitchable); - } - else if (edge->flag & STITCH_SELECTED) { - l = element1->l; - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 4], luv->uv); - - l = element2->l; - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 4 + 2], luv->uv); - - unstitchBufferIndex++; - BLI_assert(unstitchBufferIndex <= preview->num_unstitchable); - } - } - } - } - - if (ssc->states[ssc->active_object_index] != state) { - /* This is not the active object/state, exit here */ - MEM_freeN(island_stitch_data); - MEM_freeN(preview_position); - return 1; - } - - /**************************************** - * Setup preview for stitchable islands * - ****************************************/ - if (ssc->snap_islands) { - for (i = 0; i < state->element_map->totalIslands; i++) { - if (island_stitch_data[i].addedForPreview) { - int numOfIslandUVs = 0, j; - UvElement *element; - numOfIslandUVs = getNumOfIslandUvs(state->element_map, i); - element = &state->element_map->buf[state->element_map->islandIndices[i]]; - for (j = 0; j < numOfIslandUVs; j++, element++) { - stitch_set_face_preview_buffer_position(element->l->f, preview, preview_position); - } - } - } - } - - /********************************************************************* - * Setup the remaining preview buffers and fill them with the * - * appropriate data * - *********************************************************************/ - if (!final) { - BMIter liter; - BMLoop *l; - MLoopUV *luv; - unsigned int buffer_index = 0; - - /* initialize the preview buffers */ - preview->preview_polys = MEM_mallocN(preview->preview_uvs * sizeof(float) * 2, "tri_uv_stitch_prev"); - preview->uvs_per_polygon = MEM_mallocN(preview->num_polys * sizeof(*preview->uvs_per_polygon), - "tri_uv_stitch_prev"); - - preview->static_tris = MEM_mallocN(state->tris_per_island[ssc->static_island] * sizeof(float) * 6, - "static_island_preview_tris"); - - preview->num_static_tris = state->tris_per_island[ssc->static_island]; - /* will cause cancel and freeing of all data structures so OK */ - if (!preview->preview_polys) { - return 0; - } - - /* copy data from MLoopUVs to the preview display buffers */ - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - /* just to test if face was added for processing. - * uvs of unselected vertices will return NULL */ - UvElement *element = BM_uv_element_get(state->element_map, efa, BM_FACE_FIRST_LOOP(efa)); - - if (element) { - int numoftris = efa->len - 2; - int index = BM_elem_index_get(efa); - int face_preview_pos = preview_position[index].data_position; - if (face_preview_pos != STITCH_NO_PREVIEW) { - preview->uvs_per_polygon[preview_position[index].polycount_position] = efa->len; - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - copy_v2_v2(preview->preview_polys + face_preview_pos + i * 2, luv->uv); - } - } - - /* if this is the static_island on the active object */ - if (element->island == ssc->static_island) { - BMLoop *fl = BM_FACE_FIRST_LOOP(efa); - MLoopUV *fuv = CustomData_bmesh_get(&bm->ldata, fl->head.data, CD_MLOOPUV); - - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { - if (i < numoftris) { - /* using next since the first uv is already accounted for */ - BMLoop *lnext = l->next; - MLoopUV *luvnext = CustomData_bmesh_get(&bm->ldata, lnext->next->head.data, CD_MLOOPUV); - luv = CustomData_bmesh_get(&bm->ldata, lnext->head.data, CD_MLOOPUV); - - memcpy(preview->static_tris + buffer_index, fuv->uv, 2 * sizeof(float)); - memcpy(preview->static_tris + buffer_index + 2, luv->uv, 2 * sizeof(float)); - memcpy(preview->static_tris + buffer_index + 4, luvnext->uv, 2 * sizeof(float)); - buffer_index += 6; - } - else { - break; - } - } - } - } - } - } - - /****************************************************** - * Here we calculate the final coordinates of the uvs * - ******************************************************/ - - if (ssc->mode == STITCH_VERT) { - final_position = MEM_callocN(state->selection_size * sizeof(*final_position), "stitch_uv_average"); - uvfinal_map = MEM_mallocN(state->element_map->totalUVs * sizeof(*uvfinal_map), "stitch_uv_final_map"); - } - else { - final_position = MEM_callocN(state->total_separate_uvs * sizeof(*final_position), "stitch_uv_average"); - } - - /* first pass, calculate final position for stitchable uvs of the static island */ - for (i = 0; i < state->selection_size; i++) { - if (ssc->mode == STITCH_VERT) { - UvElement *element = state->selection_stack[i]; - - if (element->flag & STITCH_STITCHABLE) { - BMLoop *l; - MLoopUV *luv; - UvElement *element_iter; - - l = element->l; - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - - uvfinal_map[element - state->element_map->buf] = i; - - copy_v2_v2(final_position[i].uv, luv->uv); - final_position[i].count = 1; - - if (ssc->snap_islands && element->island == ssc->static_island && !stitch_midpoints) - continue; - - element_iter = state->element_map->vert[BM_elem_index_get(l->v)]; - - for ( ; element_iter; element_iter = element_iter->next) { - if (element_iter->separate) { - if (stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) { - l = element_iter->l; - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - if (stitch_midpoints) { - add_v2_v2(final_position[i].uv, luv->uv); - final_position[i].count++; - } - else if (element_iter->island == ssc->static_island) { - /* if multiple uvs on the static island exist, - * last checked remains. to disambiguate we need to limit or use - * edge stitch */ - copy_v2_v2(final_position[i].uv, luv->uv); - } - } - } - } - } - if (stitch_midpoints) { - final_position[i].uv[0] /= final_position[i].count; - final_position[i].uv[1] /= final_position[i].count; - } - } - else { - UvEdge *edge = state->selection_stack[i]; - - if (edge->flag & STITCH_STITCHABLE) { - MLoopUV *luv2, *luv1; - BMLoop *l; - UvEdge *edge_iter; - - l = state->uvs[edge->uv1]->l; - luv1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - l = state->uvs[edge->uv2]->l; - luv2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - - copy_v2_v2(final_position[edge->uv1].uv, luv1->uv); - copy_v2_v2(final_position[edge->uv2].uv, luv2->uv); - final_position[edge->uv1].count = 1; - final_position[edge->uv2].count = 1; - - state->uvs[edge->uv1]->flag |= STITCH_STITCHABLE; - state->uvs[edge->uv2]->flag |= STITCH_STITCHABLE; - - if (ssc->snap_islands && edge->element->island == ssc->static_island && !stitch_midpoints) - continue; - - for (edge_iter = edge->first; edge_iter; edge_iter = edge_iter->next) { - if (stitch_check_edges_state_stitchable(edge, edge_iter, ssc, state)) { - l = state->uvs[edge_iter->uv1]->l; - luv1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - l = state->uvs[edge_iter->uv2]->l; - luv2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - - if (stitch_midpoints) { - add_v2_v2(final_position[edge->uv1].uv, luv1->uv); - final_position[edge->uv1].count++; - add_v2_v2(final_position[edge->uv2].uv, luv2->uv); - final_position[edge->uv2].count++; - } - else if (edge_iter->element->island == ssc->static_island) { - copy_v2_v2(final_position[edge->uv1].uv, luv1->uv); - copy_v2_v2(final_position[edge->uv2].uv, luv2->uv); - } - } - } - } - } - } - - /* take mean position here. - * For edge case, this can't be done inside the loop for shared uvverts */ - if (ssc->mode == STITCH_EDGE && stitch_midpoints) { - for (i = 0; i < state->total_separate_uvs; i++) { - final_position[i].uv[0] /= final_position[i].count; - final_position[i].uv[1] /= final_position[i].count; - } - } - - /* second pass, calculate island rotation and translation before modifying any uvs */ - if (ssc->snap_islands) { - if (ssc->mode == STITCH_VERT) { - for (i = 0; i < state->selection_size; i++) { - UvElement *element = state->selection_stack[i]; - - if (element->flag & STITCH_STITCHABLE) { - BMLoop *l; - MLoopUV *luv; - - l = element->l; - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - - /* accumulate each islands' translation from stitchable elements. it is important to do here - * because in final pass MTFaces get modified and result is zero. */ - island_stitch_data[element->island].translation[0] += final_position[i].uv[0] - luv->uv[0]; - island_stitch_data[element->island].translation[1] += final_position[i].uv[1] - luv->uv[1]; - island_stitch_data[element->island].medianPoint[0] += luv->uv[0]; - island_stitch_data[element->island].medianPoint[1] += luv->uv[1]; - island_stitch_data[element->island].numOfElements++; - } - } - - /* only calculate rotation when an edge has been fully selected */ - for (i = 0; i < state->total_separate_edges; i++) { - UvEdge *edge = state->edges + i; - if ((edge->flag & STITCH_BOUNDARY) && - (state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) && - (state->uvs[edge->uv2]->flag & STITCH_STITCHABLE)) - { - stitch_island_calculate_edge_rotation(edge, - ssc, - state, - final_position, - uvfinal_map, - island_stitch_data); - island_stitch_data[state->uvs[edge->uv1]->island].use_edge_rotation = true; - } - } - - /* clear seams of stitched edges */ - if (final && ssc->clear_seams) { - for (i = 0; i < state->total_separate_edges; i++) { - UvEdge *edge = state->edges + i; - if ((state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) && - (state->uvs[edge->uv2]->flag & STITCH_STITCHABLE)) - { - BM_elem_flag_disable(edge->element->l->e, BM_ELEM_SEAM); - } - } - } - - for (i = 0; i < state->selection_size; i++) { - UvElement *element = state->selection_stack[i]; - if (!island_stitch_data[element->island].use_edge_rotation) { - if (element->flag & STITCH_STITCHABLE) { - stitch_island_calculate_vert_rotation(element, ssc, state, island_stitch_data); - } - } - } - } - else { - for (i = 0; i < state->total_separate_uvs; i++) { - UvElement *element = state->uvs[i]; - - if (element->flag & STITCH_STITCHABLE) { - BMLoop *l; - MLoopUV *luv; - - l = element->l; - luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); - - /* accumulate each islands' translation from stitchable elements. it is important to do here - * because in final pass MTFaces get modified and result is zero. */ - island_stitch_data[element->island].translation[0] += final_position[i].uv[0] - luv->uv[0]; - island_stitch_data[element->island].translation[1] += final_position[i].uv[1] - luv->uv[1]; - island_stitch_data[element->island].medianPoint[0] += luv->uv[0]; - island_stitch_data[element->island].medianPoint[1] += luv->uv[1]; - island_stitch_data[element->island].numOfElements++; - } - } - - for (i = 0; i < state->selection_size; i++) { - UvEdge *edge = state->selection_stack[i]; - - if (edge->flag & STITCH_STITCHABLE) { - stitch_island_calculate_edge_rotation(edge, ssc, state, final_position, NULL, island_stitch_data); - island_stitch_data[state->uvs[edge->uv1]->island].use_edge_rotation = true; - } - } - - /* clear seams of stitched edges */ - if (final && ssc->clear_seams) { - for (i = 0; i < state->selection_size; i++) { - UvEdge *edge = state->selection_stack[i]; - if (edge->flag & STITCH_STITCHABLE) { - BM_elem_flag_disable(edge->element->l->e, BM_ELEM_SEAM); - } - } - } - } - } - - /* third pass, propagate changes to coincident uvs */ - for (i = 0; i < state->selection_size; i++) { - if (ssc->mode == STITCH_VERT) { - UvElement *element = state->selection_stack[i]; - - stitch_propagate_uv_final_position(scene, element, i, preview_position, final_position, ssc, state, final); - } - else { - UvEdge *edge = state->selection_stack[i]; - - stitch_propagate_uv_final_position( - scene, state->uvs[edge->uv1], edge->uv1, preview_position, final_position, ssc, state, final); - stitch_propagate_uv_final_position( - scene, state->uvs[edge->uv2], edge->uv2, preview_position, final_position, ssc, state, final); - - edge->flag &= (STITCH_SELECTED | STITCH_BOUNDARY); - } - } - - /* final pass, calculate Island translation/rotation if needed */ - if (ssc->snap_islands) { - stitch_calculate_island_snapping(state, preview_position, preview, island_stitch_data, final); - } - - MEM_freeN(final_position); - if (ssc->mode == STITCH_VERT) { - MEM_freeN(uvfinal_map); - } - MEM_freeN(island_stitch_data); - MEM_freeN(preview_position); - - return 1; + int i; + StitchPreviewer *preview; + IslandStitchData *island_stitch_data = NULL; + int previous_island = ssc->static_island; + BMesh *bm = state->em->bm; + BMFace *efa; + BMIter iter; + UVVertAverage *final_position = NULL; + bool is_active_state = (state == ssc->states[ssc->active_object_index]); + + char stitch_midpoints = ssc->midpoints; + /* used to map uv indices to uvaverage indices for selection */ + unsigned int *uvfinal_map = NULL; + /* per face preview position in preview buffer */ + PreviewPosition *preview_position = NULL; + + /* cleanup previous preview */ + stitch_preview_delete(state->stitch_preview); + preview = state->stitch_preview = stitch_preview_init(); + if (preview == NULL) + return 0; + + preview_position = MEM_mallocN(bm->totface * sizeof(*preview_position), + "stitch_face_preview_position"); + /* each face holds its position in the preview buffer in tmp. -1 is uninitialized */ + for (i = 0; i < bm->totface; i++) { + preview_position[i].data_position = STITCH_NO_PREVIEW; + } + + island_stitch_data = MEM_callocN(sizeof(*island_stitch_data) * state->element_map->totalIslands, + "stitch_island_data"); + if (!island_stitch_data) { + return 0; + } + + /* store indices to editVerts and Faces. May be unneeded but ensuring anyway */ + BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE); + + /**************************************** + * First determine stitchability of uvs * + ****************************************/ + + for (i = 0; i < state->selection_size; i++) { + if (ssc->mode == STITCH_VERT) { + UvElement *element = (UvElement *)state->selection_stack[i]; + determine_uv_stitchability(element, ssc, state, island_stitch_data); + } + else { + UvEdge *edge = (UvEdge *)state->selection_stack[i]; + determine_uv_edge_stitchability(edge, ssc, state, island_stitch_data); + } + } + + /* remember stitchable candidates as places the 'I' button */ + /* will stop at. */ + for (int island_idx = 0; island_idx < state->element_map->totalIslands; island_idx++) { + state->island_is_stitchable[island_idx] = island_stitch_data[island_idx].stitchableCandidate ? + true : + false; + } + + if (is_active_state) { + /* set static island to one that is added for preview */ + ssc->static_island %= state->element_map->totalIslands; + while (!(island_stitch_data[ssc->static_island].stitchableCandidate)) { + ssc->static_island++; + ssc->static_island %= state->element_map->totalIslands; + /* this is entirely possible if for example limit stitching + * with no stitchable verts or no selection */ + if (ssc->static_island == previous_island) { + break; + } + } + } + + for (i = 0; i < state->selection_size; i++) { + if (ssc->mode == STITCH_VERT) { + UvElement *element = (UvElement *)state->selection_stack[i]; + if (element->flag & STITCH_STITCHABLE_CANDIDATE) { + element->flag &= ~STITCH_STITCHABLE_CANDIDATE; + stitch_validate_uv_stitchability( + element, ssc, state, island_stitch_data, preview_position); + } + else { + /* add to preview for unstitchable */ + preview->num_unstitchable++; + } + } + else { + UvEdge *edge = (UvEdge *)state->selection_stack[i]; + if (edge->flag & STITCH_STITCHABLE_CANDIDATE) { + edge->flag &= ~STITCH_STITCHABLE_CANDIDATE; + stitch_validate_edge_stitchability(edge, ssc, state, island_stitch_data, preview_position); + } + else { + preview->num_unstitchable++; + } + } + } + + /********************************************************************* + * Setup the stitchable & unstitchable preview buffers and fill * + * them with the appropriate data * + *********************************************************************/ + if (!final) { + BMLoop *l; + MLoopUV *luv; + int stitchBufferIndex = 0, unstitchBufferIndex = 0; + int preview_size = (ssc->mode == STITCH_VERT) ? 2 : 4; + /* initialize the preview buffers */ + preview->preview_stitchable = (float *)MEM_mallocN( + preview->num_stitchable * sizeof(float) * preview_size, "stitch_preview_stitchable_data"); + preview->preview_unstitchable = (float *)MEM_mallocN(preview->num_unstitchable * + sizeof(float) * preview_size, + "stitch_preview_unstitchable_data"); + + /* will cause cancel and freeing of all data structures so OK */ + if (!preview->preview_stitchable || !preview->preview_unstitchable) { + return 0; + } + + /* fill the appropriate preview buffers */ + if (ssc->mode == STITCH_VERT) { + for (i = 0; i < state->total_separate_uvs; i++) { + UvElement *element = (UvElement *)state->uvs[i]; + if (element->flag & STITCH_STITCHABLE) { + l = element->l; + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + + copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 2], luv->uv); + + stitchBufferIndex++; + } + else if (element->flag & STITCH_SELECTED) { + l = element->l; + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + + copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 2], luv->uv); + unstitchBufferIndex++; + } + } + } + else { + for (i = 0; i < state->total_separate_edges; i++) { + UvEdge *edge = state->edges + i; + UvElement *element1 = state->uvs[edge->uv1]; + UvElement *element2 = state->uvs[edge->uv2]; + + if (edge->flag & STITCH_STITCHABLE) { + l = element1->l; + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 4], luv->uv); + + l = element2->l; + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 4 + 2], luv->uv); + + stitchBufferIndex++; + BLI_assert(stitchBufferIndex <= preview->num_stitchable); + } + else if (edge->flag & STITCH_SELECTED) { + l = element1->l; + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 4], luv->uv); + + l = element2->l; + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 4 + 2], luv->uv); + + unstitchBufferIndex++; + BLI_assert(unstitchBufferIndex <= preview->num_unstitchable); + } + } + } + } + + if (ssc->states[ssc->active_object_index] != state) { + /* This is not the active object/state, exit here */ + MEM_freeN(island_stitch_data); + MEM_freeN(preview_position); + return 1; + } + + /**************************************** + * Setup preview for stitchable islands * + ****************************************/ + if (ssc->snap_islands) { + for (i = 0; i < state->element_map->totalIslands; i++) { + if (island_stitch_data[i].addedForPreview) { + int numOfIslandUVs = 0, j; + UvElement *element; + numOfIslandUVs = getNumOfIslandUvs(state->element_map, i); + element = &state->element_map->buf[state->element_map->islandIndices[i]]; + for (j = 0; j < numOfIslandUVs; j++, element++) { + stitch_set_face_preview_buffer_position(element->l->f, preview, preview_position); + } + } + } + } + + /********************************************************************* + * Setup the remaining preview buffers and fill them with the * + * appropriate data * + *********************************************************************/ + if (!final) { + BMIter liter; + BMLoop *l; + MLoopUV *luv; + unsigned int buffer_index = 0; + + /* initialize the preview buffers */ + preview->preview_polys = MEM_mallocN(preview->preview_uvs * sizeof(float) * 2, + "tri_uv_stitch_prev"); + preview->uvs_per_polygon = MEM_mallocN(preview->num_polys * sizeof(*preview->uvs_per_polygon), + "tri_uv_stitch_prev"); + + preview->static_tris = MEM_mallocN(state->tris_per_island[ssc->static_island] * sizeof(float) * + 6, + "static_island_preview_tris"); + + preview->num_static_tris = state->tris_per_island[ssc->static_island]; + /* will cause cancel and freeing of all data structures so OK */ + if (!preview->preview_polys) { + return 0; + } + + /* copy data from MLoopUVs to the preview display buffers */ + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + /* just to test if face was added for processing. + * uvs of unselected vertices will return NULL */ + UvElement *element = BM_uv_element_get(state->element_map, efa, BM_FACE_FIRST_LOOP(efa)); + + if (element) { + int numoftris = efa->len - 2; + int index = BM_elem_index_get(efa); + int face_preview_pos = preview_position[index].data_position; + if (face_preview_pos != STITCH_NO_PREVIEW) { + preview->uvs_per_polygon[preview_position[index].polycount_position] = efa->len; + BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i) + { + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + copy_v2_v2(preview->preview_polys + face_preview_pos + i * 2, luv->uv); + } + } + + /* if this is the static_island on the active object */ + if (element->island == ssc->static_island) { + BMLoop *fl = BM_FACE_FIRST_LOOP(efa); + MLoopUV *fuv = CustomData_bmesh_get(&bm->ldata, fl->head.data, CD_MLOOPUV); + + BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i) + { + if (i < numoftris) { + /* using next since the first uv is already accounted for */ + BMLoop *lnext = l->next; + MLoopUV *luvnext = CustomData_bmesh_get( + &bm->ldata, lnext->next->head.data, CD_MLOOPUV); + luv = CustomData_bmesh_get(&bm->ldata, lnext->head.data, CD_MLOOPUV); + + memcpy(preview->static_tris + buffer_index, fuv->uv, 2 * sizeof(float)); + memcpy(preview->static_tris + buffer_index + 2, luv->uv, 2 * sizeof(float)); + memcpy(preview->static_tris + buffer_index + 4, luvnext->uv, 2 * sizeof(float)); + buffer_index += 6; + } + else { + break; + } + } + } + } + } + } + + /****************************************************** + * Here we calculate the final coordinates of the uvs * + ******************************************************/ + + if (ssc->mode == STITCH_VERT) { + final_position = MEM_callocN(state->selection_size * sizeof(*final_position), + "stitch_uv_average"); + uvfinal_map = MEM_mallocN(state->element_map->totalUVs * sizeof(*uvfinal_map), + "stitch_uv_final_map"); + } + else { + final_position = MEM_callocN(state->total_separate_uvs * sizeof(*final_position), + "stitch_uv_average"); + } + + /* first pass, calculate final position for stitchable uvs of the static island */ + for (i = 0; i < state->selection_size; i++) { + if (ssc->mode == STITCH_VERT) { + UvElement *element = state->selection_stack[i]; + + if (element->flag & STITCH_STITCHABLE) { + BMLoop *l; + MLoopUV *luv; + UvElement *element_iter; + + l = element->l; + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + + uvfinal_map[element - state->element_map->buf] = i; + + copy_v2_v2(final_position[i].uv, luv->uv); + final_position[i].count = 1; + + if (ssc->snap_islands && element->island == ssc->static_island && !stitch_midpoints) + continue; + + element_iter = state->element_map->vert[BM_elem_index_get(l->v)]; + + for (; element_iter; element_iter = element_iter->next) { + if (element_iter->separate) { + if (stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) { + l = element_iter->l; + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + if (stitch_midpoints) { + add_v2_v2(final_position[i].uv, luv->uv); + final_position[i].count++; + } + else if (element_iter->island == ssc->static_island) { + /* if multiple uvs on the static island exist, + * last checked remains. to disambiguate we need to limit or use + * edge stitch */ + copy_v2_v2(final_position[i].uv, luv->uv); + } + } + } + } + } + if (stitch_midpoints) { + final_position[i].uv[0] /= final_position[i].count; + final_position[i].uv[1] /= final_position[i].count; + } + } + else { + UvEdge *edge = state->selection_stack[i]; + + if (edge->flag & STITCH_STITCHABLE) { + MLoopUV *luv2, *luv1; + BMLoop *l; + UvEdge *edge_iter; + + l = state->uvs[edge->uv1]->l; + luv1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + l = state->uvs[edge->uv2]->l; + luv2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + + copy_v2_v2(final_position[edge->uv1].uv, luv1->uv); + copy_v2_v2(final_position[edge->uv2].uv, luv2->uv); + final_position[edge->uv1].count = 1; + final_position[edge->uv2].count = 1; + + state->uvs[edge->uv1]->flag |= STITCH_STITCHABLE; + state->uvs[edge->uv2]->flag |= STITCH_STITCHABLE; + + if (ssc->snap_islands && edge->element->island == ssc->static_island && !stitch_midpoints) + continue; + + for (edge_iter = edge->first; edge_iter; edge_iter = edge_iter->next) { + if (stitch_check_edges_state_stitchable(edge, edge_iter, ssc, state)) { + l = state->uvs[edge_iter->uv1]->l; + luv1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + l = state->uvs[edge_iter->uv2]->l; + luv2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + + if (stitch_midpoints) { + add_v2_v2(final_position[edge->uv1].uv, luv1->uv); + final_position[edge->uv1].count++; + add_v2_v2(final_position[edge->uv2].uv, luv2->uv); + final_position[edge->uv2].count++; + } + else if (edge_iter->element->island == ssc->static_island) { + copy_v2_v2(final_position[edge->uv1].uv, luv1->uv); + copy_v2_v2(final_position[edge->uv2].uv, luv2->uv); + } + } + } + } + } + } + + /* take mean position here. + * For edge case, this can't be done inside the loop for shared uvverts */ + if (ssc->mode == STITCH_EDGE && stitch_midpoints) { + for (i = 0; i < state->total_separate_uvs; i++) { + final_position[i].uv[0] /= final_position[i].count; + final_position[i].uv[1] /= final_position[i].count; + } + } + + /* second pass, calculate island rotation and translation before modifying any uvs */ + if (ssc->snap_islands) { + if (ssc->mode == STITCH_VERT) { + for (i = 0; i < state->selection_size; i++) { + UvElement *element = state->selection_stack[i]; + + if (element->flag & STITCH_STITCHABLE) { + BMLoop *l; + MLoopUV *luv; + + l = element->l; + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + + /* accumulate each islands' translation from stitchable elements. it is important to do here + * because in final pass MTFaces get modified and result is zero. */ + island_stitch_data[element->island].translation[0] += final_position[i].uv[0] - + luv->uv[0]; + island_stitch_data[element->island].translation[1] += final_position[i].uv[1] - + luv->uv[1]; + island_stitch_data[element->island].medianPoint[0] += luv->uv[0]; + island_stitch_data[element->island].medianPoint[1] += luv->uv[1]; + island_stitch_data[element->island].numOfElements++; + } + } + + /* only calculate rotation when an edge has been fully selected */ + for (i = 0; i < state->total_separate_edges; i++) { + UvEdge *edge = state->edges + i; + if ((edge->flag & STITCH_BOUNDARY) && (state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) && + (state->uvs[edge->uv2]->flag & STITCH_STITCHABLE)) { + stitch_island_calculate_edge_rotation( + edge, ssc, state, final_position, uvfinal_map, island_stitch_data); + island_stitch_data[state->uvs[edge->uv1]->island].use_edge_rotation = true; + } + } + + /* clear seams of stitched edges */ + if (final && ssc->clear_seams) { + for (i = 0; i < state->total_separate_edges; i++) { + UvEdge *edge = state->edges + i; + if ((state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) && + (state->uvs[edge->uv2]->flag & STITCH_STITCHABLE)) { + BM_elem_flag_disable(edge->element->l->e, BM_ELEM_SEAM); + } + } + } + + for (i = 0; i < state->selection_size; i++) { + UvElement *element = state->selection_stack[i]; + if (!island_stitch_data[element->island].use_edge_rotation) { + if (element->flag & STITCH_STITCHABLE) { + stitch_island_calculate_vert_rotation(element, ssc, state, island_stitch_data); + } + } + } + } + else { + for (i = 0; i < state->total_separate_uvs; i++) { + UvElement *element = state->uvs[i]; + + if (element->flag & STITCH_STITCHABLE) { + BMLoop *l; + MLoopUV *luv; + + l = element->l; + luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV); + + /* accumulate each islands' translation from stitchable elements. it is important to do here + * because in final pass MTFaces get modified and result is zero. */ + island_stitch_data[element->island].translation[0] += final_position[i].uv[0] - + luv->uv[0]; + island_stitch_data[element->island].translation[1] += final_position[i].uv[1] - + luv->uv[1]; + island_stitch_data[element->island].medianPoint[0] += luv->uv[0]; + island_stitch_data[element->island].medianPoint[1] += luv->uv[1]; + island_stitch_data[element->island].numOfElements++; + } + } + + for (i = 0; i < state->selection_size; i++) { + UvEdge *edge = state->selection_stack[i]; + + if (edge->flag & STITCH_STITCHABLE) { + stitch_island_calculate_edge_rotation( + edge, ssc, state, final_position, NULL, island_stitch_data); + island_stitch_data[state->uvs[edge->uv1]->island].use_edge_rotation = true; + } + } + + /* clear seams of stitched edges */ + if (final && ssc->clear_seams) { + for (i = 0; i < state->selection_size; i++) { + UvEdge *edge = state->selection_stack[i]; + if (edge->flag & STITCH_STITCHABLE) { + BM_elem_flag_disable(edge->element->l->e, BM_ELEM_SEAM); + } + } + } + } + } + + /* third pass, propagate changes to coincident uvs */ + for (i = 0; i < state->selection_size; i++) { + if (ssc->mode == STITCH_VERT) { + UvElement *element = state->selection_stack[i]; + + stitch_propagate_uv_final_position( + scene, element, i, preview_position, final_position, ssc, state, final); + } + else { + UvEdge *edge = state->selection_stack[i]; + + stitch_propagate_uv_final_position(scene, + state->uvs[edge->uv1], + edge->uv1, + preview_position, + final_position, + ssc, + state, + final); + stitch_propagate_uv_final_position(scene, + state->uvs[edge->uv2], + edge->uv2, + preview_position, + final_position, + ssc, + state, + final); + + edge->flag &= (STITCH_SELECTED | STITCH_BOUNDARY); + } + } + + /* final pass, calculate Island translation/rotation if needed */ + if (ssc->snap_islands) { + stitch_calculate_island_snapping(state, preview_position, preview, island_stitch_data, final); + } + + MEM_freeN(final_position); + if (ssc->mode == STITCH_VERT) { + MEM_freeN(uvfinal_map); + } + MEM_freeN(island_stitch_data); + MEM_freeN(preview_position); + + return 1; } static int stitch_process_data_all(StitchStateContainer *ssc, Scene *scene, int final) { - for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { - if (!stitch_process_data(ssc, ssc->states[ob_index], scene, final)) { - return 0; - } - } + for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { + if (!stitch_process_data(ssc, ssc->states[ob_index], scene, final)) { + return 0; + } + } - return 1; + return 1; } /* Stitch hash initialization functions */ static unsigned int uv_edge_hash(const void *key) { - const UvEdge *edge = key; - return (BLI_ghashutil_uinthash(edge->uv2) + - BLI_ghashutil_uinthash(edge->uv1)); + const UvEdge *edge = key; + return (BLI_ghashutil_uinthash(edge->uv2) + BLI_ghashutil_uinthash(edge->uv1)); } static bool uv_edge_compare(const void *a, const void *b) { - const UvEdge *edge1 = a; - const UvEdge *edge2 = b; + const UvEdge *edge1 = a; + const UvEdge *edge2 = b; - if ((edge1->uv1 == edge2->uv1) && (edge1->uv2 == edge2->uv2)) { - return 0; - } - return 1; + if ((edge1->uv1 == edge2->uv1) && (edge1->uv2 == edge2->uv2)) { + return 0; + } + return 1; } /* select all common edges */ static void stitch_select_edge(UvEdge *edge, StitchState *state, int always_select) { - UvEdge *eiter; - UvEdge **selection_stack = (UvEdge **)state->selection_stack; - - for (eiter = edge->first; eiter; eiter = eiter->next) { - if (eiter->flag & STITCH_SELECTED) { - int i; - if (always_select) - continue; - - eiter->flag &= ~STITCH_SELECTED; - for (i = 0; i < state->selection_size; i++) { - if (selection_stack[i] == eiter) { - (state->selection_size)--; - selection_stack[i] = selection_stack[state->selection_size]; - break; - } - } - } - else { - eiter->flag |= STITCH_SELECTED; - selection_stack[state->selection_size++] = eiter; - } - } + UvEdge *eiter; + UvEdge **selection_stack = (UvEdge **)state->selection_stack; + + for (eiter = edge->first; eiter; eiter = eiter->next) { + if (eiter->flag & STITCH_SELECTED) { + int i; + if (always_select) + continue; + + eiter->flag &= ~STITCH_SELECTED; + for (i = 0; i < state->selection_size; i++) { + if (selection_stack[i] == eiter) { + (state->selection_size)--; + selection_stack[i] = selection_stack[state->selection_size]; + break; + } + } + } + else { + eiter->flag |= STITCH_SELECTED; + selection_stack[state->selection_size++] = eiter; + } + } } - /* Select all common uvs */ static void stitch_select_uv(UvElement *element, StitchState *state, int always_select) { - BMLoop *l; - UvElement *element_iter; - UvElement **selection_stack = (UvElement **)state->selection_stack; - - l = element->l; - - element_iter = state->element_map->vert[BM_elem_index_get(l->v)]; - /* first deselect all common uvs */ - for (; element_iter; element_iter = element_iter->next) { - if (element_iter->separate) { - /* only separators go to selection */ - if (element_iter->flag & STITCH_SELECTED) { - int i; - if (always_select) - continue; - - element_iter->flag &= ~STITCH_SELECTED; - for (i = 0; i < state->selection_size; i++) { - if (selection_stack[i] == element_iter) { - (state->selection_size)--; - selection_stack[i] = selection_stack[state->selection_size]; - break; - } - } - } - else { - element_iter->flag |= STITCH_SELECTED; - selection_stack[state->selection_size++] = element_iter; - } - } - } + BMLoop *l; + UvElement *element_iter; + UvElement **selection_stack = (UvElement **)state->selection_stack; + + l = element->l; + + element_iter = state->element_map->vert[BM_elem_index_get(l->v)]; + /* first deselect all common uvs */ + for (; element_iter; element_iter = element_iter->next) { + if (element_iter->separate) { + /* only separators go to selection */ + if (element_iter->flag & STITCH_SELECTED) { + int i; + if (always_select) + continue; + + element_iter->flag &= ~STITCH_SELECTED; + for (i = 0; i < state->selection_size; i++) { + if (selection_stack[i] == element_iter) { + (state->selection_size)--; + selection_stack[i] = selection_stack[state->selection_size]; + break; + } + } + } + else { + element_iter->flag |= STITCH_SELECTED; + selection_stack[state->selection_size++] = element_iter; + } + } + } } static void stitch_set_selection_mode(StitchState *state, const char from_stitch_mode) { - void **old_selection_stack = state->selection_stack; - int old_selection_size = state->selection_size; - state->selection_size = 0; - - if (from_stitch_mode == STITCH_VERT) { - int i; - state->selection_stack = MEM_mallocN(state->total_separate_edges * sizeof(*state->selection_stack), - "stitch_new_edge_selection_stack"); - - /* check if both elements of an edge are selected */ - for (i = 0; i < state->total_separate_edges; i++) { - UvEdge *edge = state->edges + i; - UvElement *element1 = state->uvs[edge->uv1]; - UvElement *element2 = state->uvs[edge->uv2]; - - if ((element1->flag & STITCH_SELECTED) && (element2->flag & STITCH_SELECTED)) - stitch_select_edge(edge, state, true); - } - - /* unselect selected uvelements */ - for (i = 0; i < old_selection_size; i++) { - UvElement *element = old_selection_stack[i]; - - element->flag &= ~STITCH_SELECTED; - } - } - else { - int i; - state->selection_stack = MEM_mallocN(state->total_separate_uvs * sizeof(*state->selection_stack), - "stitch_new_vert_selection_stack"); - - for (i = 0; i < old_selection_size; i++) { - UvEdge *edge = old_selection_stack[i]; - UvElement *element1 = state->uvs[edge->uv1]; - UvElement *element2 = state->uvs[edge->uv2]; - - stitch_select_uv(element1, state, true); - stitch_select_uv(element2, state, true); - - edge->flag &= ~STITCH_SELECTED; - } - } - MEM_freeN(old_selection_stack); + void **old_selection_stack = state->selection_stack; + int old_selection_size = state->selection_size; + state->selection_size = 0; + + if (from_stitch_mode == STITCH_VERT) { + int i; + state->selection_stack = MEM_mallocN(state->total_separate_edges * + sizeof(*state->selection_stack), + "stitch_new_edge_selection_stack"); + + /* check if both elements of an edge are selected */ + for (i = 0; i < state->total_separate_edges; i++) { + UvEdge *edge = state->edges + i; + UvElement *element1 = state->uvs[edge->uv1]; + UvElement *element2 = state->uvs[edge->uv2]; + + if ((element1->flag & STITCH_SELECTED) && (element2->flag & STITCH_SELECTED)) + stitch_select_edge(edge, state, true); + } + + /* unselect selected uvelements */ + for (i = 0; i < old_selection_size; i++) { + UvElement *element = old_selection_stack[i]; + + element->flag &= ~STITCH_SELECTED; + } + } + else { + int i; + state->selection_stack = MEM_mallocN(state->total_separate_uvs * + sizeof(*state->selection_stack), + "stitch_new_vert_selection_stack"); + + for (i = 0; i < old_selection_size; i++) { + UvEdge *edge = old_selection_stack[i]; + UvElement *element1 = state->uvs[edge->uv1]; + UvElement *element2 = state->uvs[edge->uv2]; + + stitch_select_uv(element1, state, true); + stitch_select_uv(element2, state, true); + + edge->flag &= ~STITCH_SELECTED; + } + } + MEM_freeN(old_selection_stack); } static void stitch_switch_selection_mode_all(StitchStateContainer *ssc) { - for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { - stitch_set_selection_mode(ssc->states[ob_index], ssc->mode); - } - - if (ssc->mode == STITCH_VERT) { - ssc->mode = STITCH_EDGE; - } - else { - ssc->mode = STITCH_VERT; - } + for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { + stitch_set_selection_mode(ssc->states[ob_index], ssc->mode); + } + + if (ssc->mode == STITCH_VERT) { + ssc->mode = STITCH_EDGE; + } + else { + ssc->mode = STITCH_VERT; + } } -static void stitch_calculate_edge_normal( - BMEditMesh *em, UvEdge *edge, float *normal, float aspect) +static void stitch_calculate_edge_normal(BMEditMesh *em, UvEdge *edge, float *normal, float aspect) { - BMLoop *l1 = edge->element->l; - MLoopUV *luv1, *luv2; - float tangent[2]; + BMLoop *l1 = edge->element->l; + MLoopUV *luv1, *luv2; + float tangent[2]; - luv1 = CustomData_bmesh_get(&em->bm->ldata, l1->head.data, CD_MLOOPUV); - luv2 = CustomData_bmesh_get(&em->bm->ldata, l1->next->head.data, CD_MLOOPUV); + luv1 = CustomData_bmesh_get(&em->bm->ldata, l1->head.data, CD_MLOOPUV); + luv2 = CustomData_bmesh_get(&em->bm->ldata, l1->next->head.data, CD_MLOOPUV); - sub_v2_v2v2(tangent, luv2->uv, luv1->uv); + sub_v2_v2v2(tangent, luv2->uv, luv1->uv); - tangent[1] /= aspect; + tangent[1] /= aspect; - normal[0] = tangent[1]; - normal[1] = -tangent[0]; + normal[0] = tangent[1]; + normal[1] = -tangent[0]; - normalize_v2(normal); + normalize_v2(normal); } /** */ static void stitch_draw_vbo(GPUVertBuf *vbo, GPUPrimType prim_type, const float col[4]) { - GPUBatch *batch = GPU_batch_create_ex(prim_type, vbo, NULL, GPU_BATCH_OWNS_VBO); - GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_UNIFORM_COLOR); - GPU_batch_uniform_4fv(batch, "color", col); - GPU_batch_draw(batch); - GPU_batch_discard(batch); + GPUBatch *batch = GPU_batch_create_ex(prim_type, vbo, NULL, GPU_BATCH_OWNS_VBO); + GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_UNIFORM_COLOR); + GPU_batch_uniform_4fv(batch, "color", col); + GPU_batch_draw(batch); + GPU_batch_discard(batch); } /* TODO make things pretier : store batches inside StitchPreviewer instead of the bare verts pos */ static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg) { - StitchStateContainer *ssc = (StitchStateContainer *)arg; - - for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { - int j, index = 0; - unsigned int num_line = 0, num_tri, tri_idx = 0, line_idx = 0; - StitchState *state = ssc->states[ob_index]; - StitchPreviewer *stitch_preview = state->stitch_preview; - GPUVertBuf *vbo, *vbo_line; - float col[4]; - - static GPUVertFormat format = { 0 }; - static unsigned int pos_id; - if (format.attr_len == 0) { - pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - } - - GPU_blend(true); - - /* Static Tris */ - if (stitch_preview->static_tris) { - UI_GetThemeColor4fv(TH_STITCH_PREVIEW_ACTIVE, col); - vbo = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(vbo, stitch_preview->num_static_tris * 3); - for (int i = 0; i < stitch_preview->num_static_tris * 3; i++) { - GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->static_tris[i * 2]); - } - stitch_draw_vbo(vbo, GPU_PRIM_TRIS, col); - } - - /* Preview Polys */ - if (stitch_preview->preview_polys) { - for (int i = 0; i < stitch_preview->num_polys; i++) - num_line += stitch_preview->uvs_per_polygon[i]; - - num_tri = num_line - 2 * stitch_preview->num_polys; - - /* we need to convert the polys into triangles / lines */ - vbo = GPU_vertbuf_create_with_format(&format); - vbo_line = GPU_vertbuf_create_with_format(&format); - - GPU_vertbuf_data_alloc(vbo, num_tri * 3); - GPU_vertbuf_data_alloc(vbo_line, num_line * 2); - - - for (int i = 0; i < stitch_preview->num_polys; i++) { - BLI_assert(stitch_preview->uvs_per_polygon[i] >= 3); - - /* Start line */ - GPU_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index]); - GPU_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + 2]); - - for (j = 1; j < stitch_preview->uvs_per_polygon[i] - 1; ++j) { - GPU_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index]); - GPU_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index + (j + 0) * 2]); - GPU_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index + (j + 1) * 2]); - - GPU_vertbuf_attr_set(vbo_line, - pos_id, - line_idx++, - &stitch_preview->preview_polys[index + (j + 0) * 2]); - GPU_vertbuf_attr_set(vbo_line, - pos_id, - line_idx++, - &stitch_preview->preview_polys[index + (j + 1) * 2]); - } - - /* Closing line */ - GPU_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index]); - /* j = uvs_per_polygon[i] - 1*/ - GPU_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + j * 2]); - - index += stitch_preview->uvs_per_polygon[i] * 2; - } - - UI_GetThemeColor4fv(TH_STITCH_PREVIEW_FACE, col); - stitch_draw_vbo(vbo, GPU_PRIM_TRIS, col); - UI_GetThemeColor4fv(TH_STITCH_PREVIEW_EDGE, col); - stitch_draw_vbo(vbo_line, GPU_PRIM_LINES, col); - } - - GPU_blend(false); - - /* draw stitch vert/lines preview */ - if (ssc->mode == STITCH_VERT) { - GPU_point_size(UI_GetThemeValuef(TH_VERTEX_SIZE) * 2.0f); - - UI_GetThemeColor4fv(TH_STITCH_PREVIEW_STITCHABLE, col); - vbo = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(vbo, stitch_preview->num_stitchable); - for (int i = 0; i < stitch_preview->num_stitchable; i++) { - GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_stitchable[i * 2]); - } - stitch_draw_vbo(vbo, GPU_PRIM_POINTS, col); - - UI_GetThemeColor4fv(TH_STITCH_PREVIEW_UNSTITCHABLE, col); - vbo = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(vbo, stitch_preview->num_unstitchable); - for (int i = 0; i < stitch_preview->num_unstitchable; i++) { - GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_unstitchable[i * 2]); - } - stitch_draw_vbo(vbo, GPU_PRIM_POINTS, col); - } - else { - UI_GetThemeColor4fv(TH_STITCH_PREVIEW_STITCHABLE, col); - vbo = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(vbo, stitch_preview->num_stitchable * 2); - for (int i = 0; i < stitch_preview->num_stitchable * 2; i++) { - GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_stitchable[i * 2]); - } - stitch_draw_vbo(vbo, GPU_PRIM_LINES, col); - - UI_GetThemeColor4fv(TH_STITCH_PREVIEW_UNSTITCHABLE, col); - vbo = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(vbo, stitch_preview->num_unstitchable * 2); - for (int i = 0; i < stitch_preview->num_unstitchable * 2; i++) { - GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_unstitchable[i * 2]); - } - stitch_draw_vbo(vbo, GPU_PRIM_LINES, col); - } - } + StitchStateContainer *ssc = (StitchStateContainer *)arg; + + for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { + int j, index = 0; + unsigned int num_line = 0, num_tri, tri_idx = 0, line_idx = 0; + StitchState *state = ssc->states[ob_index]; + StitchPreviewer *stitch_preview = state->stitch_preview; + GPUVertBuf *vbo, *vbo_line; + float col[4]; + + static GPUVertFormat format = {0}; + static unsigned int pos_id; + if (format.attr_len == 0) { + pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + } + + GPU_blend(true); + + /* Static Tris */ + if (stitch_preview->static_tris) { + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_ACTIVE, col); + vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(vbo, stitch_preview->num_static_tris * 3); + for (int i = 0; i < stitch_preview->num_static_tris * 3; i++) { + GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->static_tris[i * 2]); + } + stitch_draw_vbo(vbo, GPU_PRIM_TRIS, col); + } + + /* Preview Polys */ + if (stitch_preview->preview_polys) { + for (int i = 0; i < stitch_preview->num_polys; i++) + num_line += stitch_preview->uvs_per_polygon[i]; + + num_tri = num_line - 2 * stitch_preview->num_polys; + + /* we need to convert the polys into triangles / lines */ + vbo = GPU_vertbuf_create_with_format(&format); + vbo_line = GPU_vertbuf_create_with_format(&format); + + GPU_vertbuf_data_alloc(vbo, num_tri * 3); + GPU_vertbuf_data_alloc(vbo_line, num_line * 2); + + for (int i = 0; i < stitch_preview->num_polys; i++) { + BLI_assert(stitch_preview->uvs_per_polygon[i] >= 3); + + /* Start line */ + GPU_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index]); + GPU_vertbuf_attr_set( + vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + 2]); + + for (j = 1; j < stitch_preview->uvs_per_polygon[i] - 1; ++j) { + GPU_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index]); + GPU_vertbuf_attr_set( + vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index + (j + 0) * 2]); + GPU_vertbuf_attr_set( + vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index + (j + 1) * 2]); + + GPU_vertbuf_attr_set( + vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + (j + 0) * 2]); + GPU_vertbuf_attr_set( + vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + (j + 1) * 2]); + } + + /* Closing line */ + GPU_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index]); + /* j = uvs_per_polygon[i] - 1*/ + GPU_vertbuf_attr_set( + vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + j * 2]); + + index += stitch_preview->uvs_per_polygon[i] * 2; + } + + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_FACE, col); + stitch_draw_vbo(vbo, GPU_PRIM_TRIS, col); + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_EDGE, col); + stitch_draw_vbo(vbo_line, GPU_PRIM_LINES, col); + } + + GPU_blend(false); + + /* draw stitch vert/lines preview */ + if (ssc->mode == STITCH_VERT) { + GPU_point_size(UI_GetThemeValuef(TH_VERTEX_SIZE) * 2.0f); + + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_STITCHABLE, col); + vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(vbo, stitch_preview->num_stitchable); + for (int i = 0; i < stitch_preview->num_stitchable; i++) { + GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_stitchable[i * 2]); + } + stitch_draw_vbo(vbo, GPU_PRIM_POINTS, col); + + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_UNSTITCHABLE, col); + vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(vbo, stitch_preview->num_unstitchable); + for (int i = 0; i < stitch_preview->num_unstitchable; i++) { + GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_unstitchable[i * 2]); + } + stitch_draw_vbo(vbo, GPU_PRIM_POINTS, col); + } + else { + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_STITCHABLE, col); + vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(vbo, stitch_preview->num_stitchable * 2); + for (int i = 0; i < stitch_preview->num_stitchable * 2; i++) { + GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_stitchable[i * 2]); + } + stitch_draw_vbo(vbo, GPU_PRIM_LINES, col); + + UI_GetThemeColor4fv(TH_STITCH_PREVIEW_UNSTITCHABLE, col); + vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(vbo, stitch_preview->num_unstitchable * 2); + for (int i = 0; i < stitch_preview->num_unstitchable * 2; i++) { + GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_unstitchable[i * 2]); + } + stitch_draw_vbo(vbo, GPU_PRIM_LINES, col); + } + } } static UvEdge *uv_edge_get(BMLoop *l, StitchState *state) { - UvEdge tmp_edge; + UvEdge tmp_edge; - UvElement *element1 = BM_uv_element_get(state->element_map, l->f, l); - UvElement *element2 = BM_uv_element_get(state->element_map, l->f, l->next); + UvElement *element1 = BM_uv_element_get(state->element_map, l->f, l); + UvElement *element2 = BM_uv_element_get(state->element_map, l->f, l->next); - int uv1 = state->map[element1 - state->element_map->buf]; - int uv2 = state->map[element2 - state->element_map->buf]; + int uv1 = state->map[element1 - state->element_map->buf]; + int uv2 = state->map[element2 - state->element_map->buf]; - if (uv1 < uv2) { - tmp_edge.uv1 = uv1; - tmp_edge.uv2 = uv2; - } - else { - tmp_edge.uv1 = uv2; - tmp_edge.uv2 = uv1; - } + if (uv1 < uv2) { + tmp_edge.uv1 = uv1; + tmp_edge.uv2 = uv2; + } + else { + tmp_edge.uv1 = uv2; + tmp_edge.uv2 = uv1; + } - return BLI_ghash_lookup(state->edge_hash, &tmp_edge); + return BLI_ghash_lookup(state->edge_hash, &tmp_edge); } -static StitchState *stitch_init( - bContext *C, wmOperator *op, - StitchStateContainer *ssc, Object *obedit, StitchStateInit *state_init) +static StitchState *stitch_init(bContext *C, + wmOperator *op, + StitchStateContainer *ssc, + Object *obedit, + StitchStateInit *state_init) { - /* for fast edge lookup... */ - GHash *edge_hash; - /* ...and actual edge storage */ - UvEdge *edges; - int total_edges; - /* maps uvelements to their first coincident uv */ - int *map; - int counter = 0, i; - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - GHashIterator gh_iter; - UvEdge *all_edges; - StitchState *state; - Scene *scene = CTX_data_scene(C); - ToolSettings *ts = scene->toolsettings; - float aspx, aspy; - - BMEditMesh *em = BKE_editmesh_from_object(obedit); - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - state = MEM_callocN(sizeof(StitchState), "stitch state obj"); - - /* initialize state */ - state->obedit = obedit; - state->em = em; - - /* 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, false, true, true); - } - else { - state->element_map = BM_uv_element_map_create(state->em->bm, true, true, true); - } - if (!state->element_map) { - state_delete(state); - return NULL; - } - - ED_uvedit_get_aspect(scene, obedit, em->bm, &aspx, &aspy); - state->aspect = aspx / aspy; - - /* Count 'unique' uvs */ - for (i = 0; i < state->element_map->totalUVs; i++) { - if (state->element_map->buf[i].separate) { - counter++; - } - } - - /* explicitly set preview to NULL, - * to avoid deleting an invalid pointer on stitch_process_data */ - state->stitch_preview = NULL; - /* Allocate the unique uv buffers */ - state->uvs = MEM_mallocN(sizeof(*state->uvs) * counter, "uv_stitch_unique_uvs"); - /* internal uvs need no normals but it is hard and slow to keep a map of - * normals only for boundary uvs, so allocating for all uvs */ - state->normals = MEM_callocN(sizeof(*state->normals) * counter * 2, "uv_stitch_normals"); - state->total_separate_uvs = counter; - state->map = map = MEM_mallocN(sizeof(*map) * state->element_map->totalUVs, "uv_stitch_unique_map"); - /* Allocate the edge stack */ - edge_hash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "stitch_edge_hash"); - all_edges = MEM_mallocN(sizeof(*all_edges) * state->element_map->totalUVs, "ssc_edges"); - - if (!state->uvs || !map || !edge_hash || !all_edges) { - state_delete(state); - return NULL; - } - - /* So that we can use this as index for the UvElements */ - counter = -1; - /* initialize the unique UVs and map */ - for (i = 0; i < em->bm->totvert; i++) { - UvElement *element = state->element_map->vert[i]; - for (; element; element = element->next) { - if (element->separate) { - counter++; - state->uvs[counter] = element; - } - /* pointer arithmetic to the rescue, as always :)*/ - map[element - state->element_map->buf] = counter; - } - } - - counter = 0; - /* Now, on to generate our uv connectivity data */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!(ts->uv_flag & UV_SYNC_SELECTION) && - ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || !BM_elem_flag_test(efa, BM_ELEM_SELECT))) - { - continue; - } - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - UvElement *element = BM_uv_element_get(state->element_map, efa, l); - int offset1, itmp1 = element - state->element_map->buf; - int offset2, itmp2 = BM_uv_element_get(state->element_map, efa, l->next) - state->element_map->buf; - UvEdge *edge; - - offset1 = map[itmp1]; - offset2 = map[itmp2]; - - all_edges[counter].next = NULL; - all_edges[counter].first = NULL; - all_edges[counter].flag = 0; - all_edges[counter].element = element; - /* using an order policy, sort uvs according to address space. This avoids - * Having two different UvEdges with the same uvs on different positions */ - if (offset1 < offset2) { - all_edges[counter].uv1 = offset1; - all_edges[counter].uv2 = offset2; - } - else { - all_edges[counter].uv1 = offset2; - all_edges[counter].uv2 = offset1; - } - - edge = BLI_ghash_lookup(edge_hash, &all_edges[counter]); - if (edge) { - edge->flag = 0; - } - else { - BLI_ghash_insert(edge_hash, &all_edges[counter], &all_edges[counter]); - all_edges[counter].flag = STITCH_BOUNDARY; - } - counter++; - } - } - - total_edges = BLI_ghash_len(edge_hash); - state->edges = edges = MEM_mallocN(sizeof(*edges) * total_edges, "stitch_edges"); - - /* I assume any system will be able to at least allocate an iterator :p */ - if (!edges) { - state_delete(state); - return NULL; - } - - state->total_separate_edges = total_edges; - - /* fill the edges with data */ - i = 0; - GHASH_ITER (gh_iter, edge_hash) { - edges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter)); - } - - /* cleanup temporary stuff */ - MEM_freeN(all_edges); - - BLI_ghash_free(edge_hash, NULL, NULL); - - /* refill an edge hash to create edge connnectivity data */ - state->edge_hash = edge_hash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "stitch_edge_hash"); - for (i = 0; i < total_edges; i++) { - BLI_ghash_insert(edge_hash, edges + i, edges + i); - } - stitch_uv_edge_generate_linked_edges(edge_hash, state); - - /***** calculate 2D normals for boundary uvs *****/ - - /* we use boundary edges to calculate 2D normals. - * to disambiguate the direction of the normal, we also need - * a point "inside" the island, that can be provided by - * the winding of the polygon (assuming counter-clockwise flow). */ - - for (i = 0; i < total_edges; i++) { - UvEdge *edge = edges + i; - float normal[2]; - if (edge->flag & STITCH_BOUNDARY) { - stitch_calculate_edge_normal(em, edge, normal, state->aspect); - - add_v2_v2(state->normals + edge->uv1 * 2, normal); - add_v2_v2(state->normals + edge->uv2 * 2, normal); - - normalize_v2(state->normals + edge->uv1 * 2); - normalize_v2(state->normals + edge->uv2 * 2); - } - } - - - /***** fill selection stack *******/ - - state->selection_size = 0; - - /* Load old selection if redoing operator with different settings */ - if (state_init != NULL) { - int faceIndex, elementIndex; - UvElement *element; - enum StitchModes stored_mode = RNA_enum_get(op->ptr, "stored_mode"); - - BM_mesh_elem_table_ensure(em->bm, BM_FACE); - - int selected_count = state_init->uv_selected_count; - - if (stored_mode == STITCH_VERT) { - state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_uvs, - "uv_stitch_selection_stack"); - - while (selected_count--) { - faceIndex = state_init->to_select[selected_count].faceIndex; - elementIndex = state_init->to_select[selected_count].elementIndex; - efa = BM_face_at_index(em->bm, faceIndex); - element = BM_uv_element_get(state->element_map, - efa, - BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex)); - stitch_select_uv(element, state, 1); - } - } - else { - state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_edges, - "uv_stitch_selection_stack"); - - while (selected_count--) { - UvEdge tmp_edge, *edge; - int uv1, uv2; - faceIndex = state_init->to_select[selected_count].faceIndex; - elementIndex = state_init->to_select[selected_count].elementIndex; - efa = BM_face_at_index(em->bm, faceIndex); - element = BM_uv_element_get(state->element_map, - efa, - BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex)); - uv1 = map[element - state->element_map->buf]; - - element = BM_uv_element_get(state->element_map, - efa, - BM_iter_at_index(NULL, - BM_LOOPS_OF_FACE, - efa, - (elementIndex + 1) % efa->len)); - uv2 = map[element - state->element_map->buf]; - - if (uv1 < uv2) { - tmp_edge.uv1 = uv1; - tmp_edge.uv2 = uv2; - } - else { - tmp_edge.uv1 = uv2; - tmp_edge.uv2 = uv1; - } - - edge = BLI_ghash_lookup(edge_hash, &tmp_edge); - - stitch_select_edge(edge, state, true); - } - } - /* if user has switched the operator mode after operation, we need to convert - * the stored format */ - if (ssc->mode != stored_mode) { - stitch_set_selection_mode(state, stored_mode); - } - } - else { - if (ssc->mode == STITCH_VERT) { - state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_uvs, - "uv_stitch_selection_stack"); - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { - if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { - UvElement *element = BM_uv_element_get(state->element_map, efa, l); - if (element) { - stitch_select_uv(element, state, 1); - } - } - } - } - } - else { - state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_edges, - "uv_stitch_selection_stack"); - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!(ts->uv_flag & UV_SYNC_SELECTION) && - ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || !BM_elem_flag_test(efa, BM_ELEM_SELECT))) - { - continue; - } - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) { - UvEdge *edge = uv_edge_get(l, state); - if (edge) { - stitch_select_edge(edge, state, true); - } - } - } - } - } - } - - /***** initialize static island preview data *****/ - - state->tris_per_island = MEM_mallocN(sizeof(*state->tris_per_island) * state->element_map->totalIslands, - "stitch island tris"); - for (i = 0; i < state->element_map->totalIslands; i++) { - state->tris_per_island[i] = 0; - } - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - UvElement *element = BM_uv_element_get(state->element_map, efa, BM_FACE_FIRST_LOOP(efa)); - - if (element) { - state->tris_per_island[element->island] += (efa->len > 2) ? efa->len - 2 : 0; - } - } - - state->island_is_stitchable = MEM_callocN(sizeof(bool) * state->element_map->totalIslands, "stitch I stops"); - if (!state->island_is_stitchable) { - state_delete(state); - return NULL; - } - - if (!stitch_process_data(ssc, state, scene, false)) { - state_delete(state); - return NULL; - } - - return state; + /* for fast edge lookup... */ + GHash *edge_hash; + /* ...and actual edge storage */ + UvEdge *edges; + int total_edges; + /* maps uvelements to their first coincident uv */ + int *map; + int counter = 0, i; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + GHashIterator gh_iter; + UvEdge *all_edges; + StitchState *state; + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; + float aspx, aspy; + + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + state = MEM_callocN(sizeof(StitchState), "stitch state obj"); + + /* initialize state */ + state->obedit = obedit; + state->em = em; + + /* 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, false, true, true); + } + else { + state->element_map = BM_uv_element_map_create(state->em->bm, true, true, true); + } + if (!state->element_map) { + state_delete(state); + return NULL; + } + + ED_uvedit_get_aspect(scene, obedit, em->bm, &aspx, &aspy); + state->aspect = aspx / aspy; + + /* Count 'unique' uvs */ + for (i = 0; i < state->element_map->totalUVs; i++) { + if (state->element_map->buf[i].separate) { + counter++; + } + } + + /* explicitly set preview to NULL, + * to avoid deleting an invalid pointer on stitch_process_data */ + state->stitch_preview = NULL; + /* Allocate the unique uv buffers */ + state->uvs = MEM_mallocN(sizeof(*state->uvs) * counter, "uv_stitch_unique_uvs"); + /* internal uvs need no normals but it is hard and slow to keep a map of + * normals only for boundary uvs, so allocating for all uvs */ + state->normals = MEM_callocN(sizeof(*state->normals) * counter * 2, "uv_stitch_normals"); + state->total_separate_uvs = counter; + state->map = map = MEM_mallocN(sizeof(*map) * state->element_map->totalUVs, + "uv_stitch_unique_map"); + /* Allocate the edge stack */ + edge_hash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "stitch_edge_hash"); + all_edges = MEM_mallocN(sizeof(*all_edges) * state->element_map->totalUVs, "ssc_edges"); + + if (!state->uvs || !map || !edge_hash || !all_edges) { + state_delete(state); + return NULL; + } + + /* So that we can use this as index for the UvElements */ + counter = -1; + /* initialize the unique UVs and map */ + for (i = 0; i < em->bm->totvert; i++) { + UvElement *element = state->element_map->vert[i]; + for (; element; element = element->next) { + if (element->separate) { + counter++; + state->uvs[counter] = element; + } + /* pointer arithmetic to the rescue, as always :)*/ + map[element - state->element_map->buf] = counter; + } + } + + counter = 0; + /* Now, on to generate our uv connectivity data */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!(ts->uv_flag & UV_SYNC_SELECTION) && + ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || !BM_elem_flag_test(efa, BM_ELEM_SELECT))) { + continue; + } + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + UvElement *element = BM_uv_element_get(state->element_map, efa, l); + int offset1, itmp1 = element - state->element_map->buf; + int offset2, + itmp2 = BM_uv_element_get(state->element_map, efa, l->next) - state->element_map->buf; + UvEdge *edge; + + offset1 = map[itmp1]; + offset2 = map[itmp2]; + + all_edges[counter].next = NULL; + all_edges[counter].first = NULL; + all_edges[counter].flag = 0; + all_edges[counter].element = element; + /* using an order policy, sort uvs according to address space. This avoids + * Having two different UvEdges with the same uvs on different positions */ + if (offset1 < offset2) { + all_edges[counter].uv1 = offset1; + all_edges[counter].uv2 = offset2; + } + else { + all_edges[counter].uv1 = offset2; + all_edges[counter].uv2 = offset1; + } + + edge = BLI_ghash_lookup(edge_hash, &all_edges[counter]); + if (edge) { + edge->flag = 0; + } + else { + BLI_ghash_insert(edge_hash, &all_edges[counter], &all_edges[counter]); + all_edges[counter].flag = STITCH_BOUNDARY; + } + counter++; + } + } + + total_edges = BLI_ghash_len(edge_hash); + state->edges = edges = MEM_mallocN(sizeof(*edges) * total_edges, "stitch_edges"); + + /* I assume any system will be able to at least allocate an iterator :p */ + if (!edges) { + state_delete(state); + return NULL; + } + + state->total_separate_edges = total_edges; + + /* fill the edges with data */ + i = 0; + GHASH_ITER (gh_iter, edge_hash) { + edges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter)); + } + + /* cleanup temporary stuff */ + MEM_freeN(all_edges); + + BLI_ghash_free(edge_hash, NULL, NULL); + + /* refill an edge hash to create edge connnectivity data */ + state->edge_hash = edge_hash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "stitch_edge_hash"); + for (i = 0; i < total_edges; i++) { + BLI_ghash_insert(edge_hash, edges + i, edges + i); + } + stitch_uv_edge_generate_linked_edges(edge_hash, state); + + /***** calculate 2D normals for boundary uvs *****/ + + /* we use boundary edges to calculate 2D normals. + * to disambiguate the direction of the normal, we also need + * a point "inside" the island, that can be provided by + * the winding of the polygon (assuming counter-clockwise flow). */ + + for (i = 0; i < total_edges; i++) { + UvEdge *edge = edges + i; + float normal[2]; + if (edge->flag & STITCH_BOUNDARY) { + stitch_calculate_edge_normal(em, edge, normal, state->aspect); + + add_v2_v2(state->normals + edge->uv1 * 2, normal); + add_v2_v2(state->normals + edge->uv2 * 2, normal); + + normalize_v2(state->normals + edge->uv1 * 2); + normalize_v2(state->normals + edge->uv2 * 2); + } + } + + /***** fill selection stack *******/ + + state->selection_size = 0; + + /* Load old selection if redoing operator with different settings */ + if (state_init != NULL) { + int faceIndex, elementIndex; + UvElement *element; + enum StitchModes stored_mode = RNA_enum_get(op->ptr, "stored_mode"); + + BM_mesh_elem_table_ensure(em->bm, BM_FACE); + + int selected_count = state_init->uv_selected_count; + + if (stored_mode == STITCH_VERT) { + state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * + state->total_separate_uvs, + "uv_stitch_selection_stack"); + + while (selected_count--) { + faceIndex = state_init->to_select[selected_count].faceIndex; + elementIndex = state_init->to_select[selected_count].elementIndex; + efa = BM_face_at_index(em->bm, faceIndex); + element = BM_uv_element_get( + state->element_map, efa, BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex)); + stitch_select_uv(element, state, 1); + } + } + else { + state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * + state->total_separate_edges, + "uv_stitch_selection_stack"); + + while (selected_count--) { + UvEdge tmp_edge, *edge; + int uv1, uv2; + faceIndex = state_init->to_select[selected_count].faceIndex; + elementIndex = state_init->to_select[selected_count].elementIndex; + efa = BM_face_at_index(em->bm, faceIndex); + element = BM_uv_element_get( + state->element_map, efa, BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex)); + uv1 = map[element - state->element_map->buf]; + + element = BM_uv_element_get( + state->element_map, + efa, + BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, (elementIndex + 1) % efa->len)); + uv2 = map[element - state->element_map->buf]; + + if (uv1 < uv2) { + tmp_edge.uv1 = uv1; + tmp_edge.uv2 = uv2; + } + else { + tmp_edge.uv1 = uv2; + tmp_edge.uv2 = uv1; + } + + edge = BLI_ghash_lookup(edge_hash, &tmp_edge); + + stitch_select_edge(edge, state, true); + } + } + /* if user has switched the operator mode after operation, we need to convert + * the stored format */ + if (ssc->mode != stored_mode) { + stitch_set_selection_mode(state, stored_mode); + } + } + else { + if (ssc->mode == STITCH_VERT) { + state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * + state->total_separate_uvs, + "uv_stitch_selection_stack"); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i) + { + if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + UvElement *element = BM_uv_element_get(state->element_map, efa, l); + if (element) { + stitch_select_uv(element, state, 1); + } + } + } + } + } + else { + state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * + state->total_separate_edges, + "uv_stitch_selection_stack"); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!(ts->uv_flag & UV_SYNC_SELECTION) && ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || + !BM_elem_flag_test(efa, BM_ELEM_SELECT))) { + continue; + } + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) { + UvEdge *edge = uv_edge_get(l, state); + if (edge) { + stitch_select_edge(edge, state, true); + } + } + } + } + } + } + + /***** initialize static island preview data *****/ + + state->tris_per_island = MEM_mallocN( + sizeof(*state->tris_per_island) * state->element_map->totalIslands, "stitch island tris"); + for (i = 0; i < state->element_map->totalIslands; i++) { + state->tris_per_island[i] = 0; + } + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + UvElement *element = BM_uv_element_get(state->element_map, efa, BM_FACE_FIRST_LOOP(efa)); + + if (element) { + state->tris_per_island[element->island] += (efa->len > 2) ? efa->len - 2 : 0; + } + } + + state->island_is_stitchable = MEM_callocN(sizeof(bool) * state->element_map->totalIslands, + "stitch I stops"); + if (!state->island_is_stitchable) { + state_delete(state); + return NULL; + } + + if (!stitch_process_data(ssc, state, scene, false)) { + state_delete(state); + return NULL; + } + + return state; } static bool goto_next_island(StitchStateContainer *ssc) { - StitchState *active_state = ssc->states[ssc->active_object_index]; - StitchState *original_active_state = active_state; - - int original_island = ssc->static_island; - - do { - ssc->static_island++; - if (ssc->static_island >= active_state->element_map->totalIslands) { - /* go to next object */ - ssc->active_object_index++; - ssc->active_object_index %= ssc->objects_len; - - active_state = ssc->states[ssc->active_object_index]; - ssc->static_island = 0; - } - - if (active_state->island_is_stitchable[ssc->static_island]) { - /* We're at an island to make active */ - return true; - } - } while (!(active_state == original_active_state && - ssc->static_island == original_island)); - - return false; + StitchState *active_state = ssc->states[ssc->active_object_index]; + StitchState *original_active_state = active_state; + + int original_island = ssc->static_island; + + do { + ssc->static_island++; + if (ssc->static_island >= active_state->element_map->totalIslands) { + /* go to next object */ + ssc->active_object_index++; + ssc->active_object_index %= ssc->objects_len; + + active_state = ssc->states[ssc->active_object_index]; + ssc->static_island = 0; + } + + if (active_state->island_is_stitchable[ssc->static_island]) { + /* We're at an island to make active */ + return true; + } + } while (!(active_state == original_active_state && ssc->static_island == original_island)); + + return false; } static int stitch_init_all(bContext *C, wmOperator *op) { - ARegion *ar = CTX_wm_region(C); - if (!ar) - return 0; - - Scene *scene = CTX_data_scene(C); - ToolSettings *ts = scene->toolsettings; - - StitchStateContainer *ssc = MEM_callocN(sizeof(StitchStateContainer), "stitch collection"); - - op->customdata = ssc; - - ssc->use_limit = RNA_boolean_get(op->ptr, "use_limit"); - ssc->limit_dist = RNA_float_get(op->ptr, "limit"); - ssc->snap_islands = RNA_boolean_get(op->ptr, "snap_islands"); - ssc->midpoints = RNA_boolean_get(op->ptr, "midpoint_snap"); - ssc->clear_seams = RNA_boolean_get(op->ptr, "clear_seams"); - ssc->active_object_index = RNA_int_get(op->ptr, "active_object_index"); - ssc->static_island = 0; - - if (RNA_struct_property_is_set(op->ptr, "mode")) { - ssc->mode = RNA_enum_get(op->ptr, "mode"); - } - else { - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (ts->selectmode & SCE_SELECT_VERTEX) - ssc->mode = STITCH_VERT; - else - ssc->mode = STITCH_EDGE; - } - else { - if (ts->uv_selectmode & UV_SELECT_VERTEX) { - ssc->mode = STITCH_VERT; - } - else { - ssc->mode = STITCH_EDGE; - } - } - } - - ssc->objects_len = 0; - ssc->states = NULL; - - ViewLayer *view_layer = CTX_data_view_layer(C); - View3D *v3d = CTX_wm_view3d(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, v3d, &objects_len); - - if (objects_len == 0) { - MEM_freeN(objects); - state_delete_all(ssc); - return 0; - } - - ssc->objects = MEM_callocN(sizeof(Object *) * objects_len, "Object *ssc->objects"); - ssc->states = MEM_callocN(sizeof(StitchState *) * objects_len, "StitchState"); - ssc->objects_len = 0; - - int *objs_selection_count = NULL; - UvElementID *selected_uvs_arr = NULL; - StitchStateInit *state_init = NULL; - - if (RNA_struct_property_is_set(op->ptr, "selection") && - RNA_struct_property_is_set(op->ptr, "objects_selection_count")) - { - /* Retrieve list of selected UVs, one list contains all selected UVs - * for all objects. */ - - objs_selection_count = MEM_mallocN(sizeof(int *) * objects_len, "objects_selection_count"); - RNA_int_get_array(op->ptr, "objects_selection_count", objs_selection_count); - - int total_selected = 0; - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - total_selected += objs_selection_count[ob_index]; - } - - selected_uvs_arr = MEM_callocN(sizeof(UvElementID) * total_selected, "selected_uvs_arr"); - int sel_idx = 0; - RNA_BEGIN (op->ptr, itemptr, "selection") - { - BLI_assert(sel_idx < total_selected); - selected_uvs_arr[sel_idx].faceIndex = RNA_int_get(&itemptr, "face_index"); - selected_uvs_arr[sel_idx].elementIndex = RNA_int_get(&itemptr, "element_index"); - sel_idx++; - } - RNA_END; - - RNA_collection_clear(op->ptr, "selection"); - - state_init = MEM_callocN(sizeof(StitchStateInit), "UV_init_selected"); - state_init->to_select = selected_uvs_arr; - } - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - - if (state_init != NULL) { - state_init->uv_selected_count = objs_selection_count[ob_index]; - } - - StitchState *stitch_state_ob = stitch_init(C, op, ssc, obedit, state_init); - - if (state_init != NULL) { - /* Move pointer to beginning of next object's data. */ - state_init->to_select += state_init->uv_selected_count; - } - - if (stitch_state_ob) { - ssc->objects[ssc->objects_len] = obedit; - ssc->states[ssc->objects_len] = stitch_state_ob; - ssc->objects_len++; - } - } - - MEM_freeN(objects); - MEM_SAFE_FREE(selected_uvs_arr); - MEM_SAFE_FREE(objs_selection_count); - MEM_SAFE_FREE(state_init); - - if (ssc->objects_len == 0) { - state_delete_all(ssc); - return 0; - } - - ssc->active_object_index %= ssc->objects_len; - - ssc->static_island = RNA_int_get(op->ptr, "static_island"); - - StitchState *state = ssc->states[ssc->active_object_index]; - ssc->static_island %= state->element_map->totalIslands; - - /* If the initial active object doesn't have any stitchable islands */ - /* then no active island will be seen in the UI. Make sure we're on */ - /* a stitchable object and island. */ - if (!state->island_is_stitchable[ssc->static_island]) { - goto_next_island(ssc); - state = ssc->states[ssc->active_object_index]; - } - - /* process active stitchobj again now that it can detect it's the active stitchobj */ - stitch_process_data(ssc, state, scene, false); - - stitch_update_header(ssc, C); - - ssc->draw_handle = ED_region_draw_cb_activate(ar->type, stitch_draw, ssc, REGION_DRAW_POST_VIEW); - - return 1; + ARegion *ar = CTX_wm_region(C); + if (!ar) + return 0; + + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; + + StitchStateContainer *ssc = MEM_callocN(sizeof(StitchStateContainer), "stitch collection"); + + op->customdata = ssc; + + ssc->use_limit = RNA_boolean_get(op->ptr, "use_limit"); + ssc->limit_dist = RNA_float_get(op->ptr, "limit"); + ssc->snap_islands = RNA_boolean_get(op->ptr, "snap_islands"); + ssc->midpoints = RNA_boolean_get(op->ptr, "midpoint_snap"); + ssc->clear_seams = RNA_boolean_get(op->ptr, "clear_seams"); + ssc->active_object_index = RNA_int_get(op->ptr, "active_object_index"); + ssc->static_island = 0; + + if (RNA_struct_property_is_set(op->ptr, "mode")) { + ssc->mode = RNA_enum_get(op->ptr, "mode"); + } + else { + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (ts->selectmode & SCE_SELECT_VERTEX) + ssc->mode = STITCH_VERT; + else + ssc->mode = STITCH_EDGE; + } + else { + if (ts->uv_selectmode & UV_SELECT_VERTEX) { + ssc->mode = STITCH_VERT; + } + else { + ssc->mode = STITCH_EDGE; + } + } + } + + ssc->objects_len = 0; + ssc->states = NULL; + + ViewLayer *view_layer = CTX_data_view_layer(C); + View3D *v3d = CTX_wm_view3d(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, v3d, &objects_len); + + if (objects_len == 0) { + MEM_freeN(objects); + state_delete_all(ssc); + return 0; + } + + ssc->objects = MEM_callocN(sizeof(Object *) * objects_len, "Object *ssc->objects"); + ssc->states = MEM_callocN(sizeof(StitchState *) * objects_len, "StitchState"); + ssc->objects_len = 0; + + int *objs_selection_count = NULL; + UvElementID *selected_uvs_arr = NULL; + StitchStateInit *state_init = NULL; + + if (RNA_struct_property_is_set(op->ptr, "selection") && + RNA_struct_property_is_set(op->ptr, "objects_selection_count")) { + /* Retrieve list of selected UVs, one list contains all selected UVs + * for all objects. */ + + objs_selection_count = MEM_mallocN(sizeof(int *) * objects_len, "objects_selection_count"); + RNA_int_get_array(op->ptr, "objects_selection_count", objs_selection_count); + + int total_selected = 0; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + total_selected += objs_selection_count[ob_index]; + } + + selected_uvs_arr = MEM_callocN(sizeof(UvElementID) * total_selected, "selected_uvs_arr"); + int sel_idx = 0; + RNA_BEGIN (op->ptr, itemptr, "selection") { + BLI_assert(sel_idx < total_selected); + selected_uvs_arr[sel_idx].faceIndex = RNA_int_get(&itemptr, "face_index"); + selected_uvs_arr[sel_idx].elementIndex = RNA_int_get(&itemptr, "element_index"); + sel_idx++; + } + RNA_END; + + RNA_collection_clear(op->ptr, "selection"); + + state_init = MEM_callocN(sizeof(StitchStateInit), "UV_init_selected"); + state_init->to_select = selected_uvs_arr; + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + + if (state_init != NULL) { + state_init->uv_selected_count = objs_selection_count[ob_index]; + } + + StitchState *stitch_state_ob = stitch_init(C, op, ssc, obedit, state_init); + + if (state_init != NULL) { + /* Move pointer to beginning of next object's data. */ + state_init->to_select += state_init->uv_selected_count; + } + + if (stitch_state_ob) { + ssc->objects[ssc->objects_len] = obedit; + ssc->states[ssc->objects_len] = stitch_state_ob; + ssc->objects_len++; + } + } + + MEM_freeN(objects); + MEM_SAFE_FREE(selected_uvs_arr); + MEM_SAFE_FREE(objs_selection_count); + MEM_SAFE_FREE(state_init); + + if (ssc->objects_len == 0) { + state_delete_all(ssc); + return 0; + } + + ssc->active_object_index %= ssc->objects_len; + + ssc->static_island = RNA_int_get(op->ptr, "static_island"); + + StitchState *state = ssc->states[ssc->active_object_index]; + ssc->static_island %= state->element_map->totalIslands; + + /* If the initial active object doesn't have any stitchable islands */ + /* then no active island will be seen in the UI. Make sure we're on */ + /* a stitchable object and island. */ + if (!state->island_is_stitchable[ssc->static_island]) { + goto_next_island(ssc); + state = ssc->states[ssc->active_object_index]; + } + + /* process active stitchobj again now that it can detect it's the active stitchobj */ + stitch_process_data(ssc, state, scene, false); + + stitch_update_header(ssc, C); + + ssc->draw_handle = ED_region_draw_cb_activate(ar->type, stitch_draw, ssc, REGION_DRAW_POST_VIEW); + + return 1; } static int stitch_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (!stitch_init_all(C, op)) - return OPERATOR_CANCELLED; + if (!stitch_init_all(C, op)) + return OPERATOR_CANCELLED; - WM_event_add_modal_handler(C, op); + WM_event_add_modal_handler(C, op); - Scene *scene = CTX_data_scene(C); - ToolSettings *ts = scene->toolsettings; - const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; + const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; - StitchStateContainer *ssc = (StitchStateContainer *)op->customdata; + StitchStateContainer *ssc = (StitchStateContainer *)op->customdata; - for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { - StitchState *state = ssc->states[ob_index]; - Object *obedit = state->obedit; - BMEditMesh *em = BKE_editmesh_from_object(obedit); + for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { + StitchState *state = ssc->states[ob_index]; + Object *obedit = state->obedit; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (synced_selection && (em->bm->totvertsel == 0)) { - continue; - } + if (synced_selection && (em->bm->totvertsel == 0)) { + continue; + } - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - } + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } - return OPERATOR_RUNNING_MODAL; + return OPERATOR_RUNNING_MODAL; } static void stitch_exit(bContext *C, wmOperator *op, int finished) { - Scene *scene = CTX_data_scene(C); - SpaceImage *sima = CTX_wm_space_image(C); - ScrArea *sa = CTX_wm_area(C); - - StitchStateContainer *ssc = (StitchStateContainer *)op->customdata; - - if (finished) { - RNA_float_set(op->ptr, "limit", ssc->limit_dist); - RNA_boolean_set(op->ptr, "use_limit", ssc->use_limit); - RNA_boolean_set(op->ptr, "snap_islands", ssc->snap_islands); - RNA_boolean_set(op->ptr, "midpoint_snap", ssc->midpoints); - RNA_boolean_set(op->ptr, "clear_seams", ssc->clear_seams); - RNA_enum_set(op->ptr, "mode", ssc->mode); - RNA_enum_set(op->ptr, "stored_mode", ssc->mode); - RNA_int_set(op->ptr, "active_object_index", ssc->active_object_index); - - RNA_int_set(op->ptr, "static_island", ssc->static_island); - - int *objs_selection_count = NULL; - objs_selection_count = MEM_mallocN(sizeof(int *) * ssc->objects_len, "objects_selection_count"); - - /* Store selection for re-execution of stitch - * - Store all selected UVs in "selection" - * - Store how many each object has in "objects_selection_count". */ - RNA_collection_clear(op->ptr, "selection"); - for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { - StitchState *state = ssc->states[ob_index]; - Object *obedit = state->obedit; - - PointerRNA itemptr; - for (int i = 0; i < state->selection_size; i++) { - UvElement *element; - - if (ssc->mode == STITCH_VERT) { - element = state->selection_stack[i]; - } - else { - element = ((UvEdge *)state->selection_stack[i])->element; - } - RNA_collection_add(op->ptr, "selection", &itemptr); - - RNA_int_set(&itemptr, "face_index", BM_elem_index_get(element->l->f)); - RNA_int_set(&itemptr, "element_index", element->loop_of_poly_index); - } - uvedit_live_unwrap_update(sima, scene, obedit); - - objs_selection_count[ob_index] = state->selection_size; - } - - PropertyRNA *prop = RNA_struct_find_property(op->ptr, "objects_selection_count"); - RNA_def_property_array(prop, ssc->objects_len); - RNA_int_set_array(op->ptr, "objects_selection_count", objs_selection_count); - MEM_freeN(objs_selection_count); - } - - if (sa) - ED_workspace_status_text(C, NULL); - - ED_region_draw_cb_exit(CTX_wm_region(C)->type, ssc->draw_handle); - - ToolSettings *ts = scene->toolsettings; - const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; - - for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { - StitchState *state = ssc->states[ob_index]; - Object *obedit = state->obedit; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (synced_selection && (em->bm->totvertsel == 0)) { - continue; - } - - DEG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - } - - state_delete_all(ssc); - - op->customdata = NULL; + Scene *scene = CTX_data_scene(C); + SpaceImage *sima = CTX_wm_space_image(C); + ScrArea *sa = CTX_wm_area(C); + + StitchStateContainer *ssc = (StitchStateContainer *)op->customdata; + + if (finished) { + RNA_float_set(op->ptr, "limit", ssc->limit_dist); + RNA_boolean_set(op->ptr, "use_limit", ssc->use_limit); + RNA_boolean_set(op->ptr, "snap_islands", ssc->snap_islands); + RNA_boolean_set(op->ptr, "midpoint_snap", ssc->midpoints); + RNA_boolean_set(op->ptr, "clear_seams", ssc->clear_seams); + RNA_enum_set(op->ptr, "mode", ssc->mode); + RNA_enum_set(op->ptr, "stored_mode", ssc->mode); + RNA_int_set(op->ptr, "active_object_index", ssc->active_object_index); + + RNA_int_set(op->ptr, "static_island", ssc->static_island); + + int *objs_selection_count = NULL; + objs_selection_count = MEM_mallocN(sizeof(int *) * ssc->objects_len, + "objects_selection_count"); + + /* Store selection for re-execution of stitch + * - Store all selected UVs in "selection" + * - Store how many each object has in "objects_selection_count". */ + RNA_collection_clear(op->ptr, "selection"); + for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { + StitchState *state = ssc->states[ob_index]; + Object *obedit = state->obedit; + + PointerRNA itemptr; + for (int i = 0; i < state->selection_size; i++) { + UvElement *element; + + if (ssc->mode == STITCH_VERT) { + element = state->selection_stack[i]; + } + else { + element = ((UvEdge *)state->selection_stack[i])->element; + } + RNA_collection_add(op->ptr, "selection", &itemptr); + + RNA_int_set(&itemptr, "face_index", BM_elem_index_get(element->l->f)); + RNA_int_set(&itemptr, "element_index", element->loop_of_poly_index); + } + uvedit_live_unwrap_update(sima, scene, obedit); + + objs_selection_count[ob_index] = state->selection_size; + } + + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "objects_selection_count"); + RNA_def_property_array(prop, ssc->objects_len); + RNA_int_set_array(op->ptr, "objects_selection_count", objs_selection_count); + MEM_freeN(objs_selection_count); + } + + if (sa) + ED_workspace_status_text(C, NULL); + + ED_region_draw_cb_exit(CTX_wm_region(C)->type, ssc->draw_handle); + + ToolSettings *ts = scene->toolsettings; + const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0; + + for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { + StitchState *state = ssc->states[ob_index]; + Object *obedit = state->obedit; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (synced_selection && (em->bm->totvertsel == 0)) { + continue; + } + + DEG_id_tag_update(obedit->data, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + } + + state_delete_all(ssc); + + op->customdata = NULL; } - static void stitch_cancel(bContext *C, wmOperator *op) { - stitch_exit(C, op, 0); + stitch_exit(C, op, 0); } - static int stitch_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - - if (!stitch_init_all(C, op)) - return OPERATOR_CANCELLED; - if (stitch_process_data_all((StitchStateContainer *)op->customdata, scene, 1)) { - stitch_exit(C, op, 1); - return OPERATOR_FINISHED; - } - else { - stitch_cancel(C, op); - return OPERATOR_CANCELLED; - } + Scene *scene = CTX_data_scene(C); + + if (!stitch_init_all(C, op)) + return OPERATOR_CANCELLED; + if (stitch_process_data_all((StitchStateContainer *)op->customdata, scene, 1)) { + stitch_exit(C, op, 1); + return OPERATOR_FINISHED; + } + else { + stitch_cancel(C, op); + return OPERATOR_CANCELLED; + } } -static StitchState *stitch_select( - bContext *C, Scene *scene, const wmEvent *event, StitchStateContainer *ssc) +static StitchState *stitch_select(bContext *C, + Scene *scene, + const wmEvent *event, + StitchStateContainer *ssc) { - /* add uv under mouse to processed uv's */ - float co[2]; - UvNearestHit hit = UV_NEAREST_HIT_INIT; - ARegion *ar = CTX_wm_region(C); - Image *ima = CTX_data_edit_image(C); - - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); - - if (ssc->mode == STITCH_VERT) { - if (uv_find_nearest_vert_multi(scene, ima, ssc->objects, ssc->objects_len, co, 0.0f, &hit)) { - /* Add vertex to selection, deselect all common uv's of vert other than selected and - * update the preview. This behavior was decided so that you can do stuff like deselect - * the opposite stitchable vertex and the initial still gets deselected */ - - /* find StitchState from hit->ob */ - StitchState *state = NULL; - for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { - if (hit.ob == ssc->objects[ob_index]) { - state = ssc->states[ob_index]; - break; - } - } - - /* This works due to setting of tmp in find nearest uv vert */ - UvElement *element = BM_uv_element_get(state->element_map, hit.efa, hit.l); - stitch_select_uv(element, state, false); - - return state; - } - } - else if (uv_find_nearest_edge_multi(scene, ima, ssc->objects, ssc->objects_len, co, &hit)) { - /* find StitchState from hit->ob */ - StitchState *state = NULL; - for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { - if (hit.ob == ssc->objects[ob_index]) { - state = ssc->states[ob_index]; - break; - } - } - - UvEdge *edge = uv_edge_get(hit.l, state); - stitch_select_edge(edge, state, false); - - return state; - } - - return NULL; + /* add uv under mouse to processed uv's */ + float co[2]; + UvNearestHit hit = UV_NEAREST_HIT_INIT; + ARegion *ar = CTX_wm_region(C); + Image *ima = CTX_data_edit_image(C); + + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); + + if (ssc->mode == STITCH_VERT) { + if (uv_find_nearest_vert_multi(scene, ima, ssc->objects, ssc->objects_len, co, 0.0f, &hit)) { + /* Add vertex to selection, deselect all common uv's of vert other than selected and + * update the preview. This behavior was decided so that you can do stuff like deselect + * the opposite stitchable vertex and the initial still gets deselected */ + + /* find StitchState from hit->ob */ + StitchState *state = NULL; + for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { + if (hit.ob == ssc->objects[ob_index]) { + state = ssc->states[ob_index]; + break; + } + } + + /* This works due to setting of tmp in find nearest uv vert */ + UvElement *element = BM_uv_element_get(state->element_map, hit.efa, hit.l); + stitch_select_uv(element, state, false); + + return state; + } + } + else if (uv_find_nearest_edge_multi(scene, ima, ssc->objects, ssc->objects_len, co, &hit)) { + /* find StitchState from hit->ob */ + StitchState *state = NULL; + for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) { + if (hit.ob == ssc->objects[ob_index]) { + state = ssc->states[ob_index]; + break; + } + } + + UvEdge *edge = uv_edge_get(hit.l, state); + stitch_select_edge(edge, state, false); + + return state; + } + + return NULL; } static int stitch_modal(bContext *C, wmOperator *op, const wmEvent *event) { - StitchStateContainer *ssc; - Scene *scene = CTX_data_scene(C); - - ssc = op->customdata; - StitchState *active_state = ssc->states[ssc->active_object_index]; - - switch (event->type) { - case MIDDLEMOUSE: - return OPERATOR_PASS_THROUGH; - - /* Cancel */ - case ESCKEY: - stitch_cancel(C, op); - return OPERATOR_CANCELLED; - - case LEFTMOUSE: - case PADENTER: - case RETKEY: - if (event->val == KM_PRESS) { - if (stitch_process_data(ssc, active_state, scene, true)) { - stitch_exit(C, op, 1); - return OPERATOR_FINISHED; - } - else { - stitch_cancel(C, op); - return OPERATOR_CANCELLED; - } - } - else { - return OPERATOR_PASS_THROUGH; - } - /* Increase limit */ - case PADPLUSKEY: - case WHEELUPMOUSE: - if (event->val == KM_PRESS && event->alt) { - ssc->limit_dist += 0.01f; - if (!stitch_process_data(ssc, active_state, scene, false)) { - stitch_cancel(C, op); - return OPERATOR_CANCELLED; - } - break; - } - else { - return OPERATOR_PASS_THROUGH; - } - /* Decrease limit */ - case PADMINUS: - case WHEELDOWNMOUSE: - if (event->val == KM_PRESS && event->alt) { - ssc->limit_dist -= 0.01f; - ssc->limit_dist = MAX2(0.01f, ssc->limit_dist); - if (!stitch_process_data(ssc, active_state, scene, false)) { - stitch_cancel(C, op); - return OPERATOR_CANCELLED; - } - break; - } - else { - return OPERATOR_PASS_THROUGH; - } - - /* Use Limit (Default off) */ - case LKEY: - if (event->val == KM_PRESS) { - ssc->use_limit = !ssc->use_limit; - if (!stitch_process_data(ssc, active_state, scene, false)) { - stitch_cancel(C, op); - return OPERATOR_CANCELLED; - } - break; - } - return OPERATOR_RUNNING_MODAL; - - case IKEY: - if (event->val == KM_PRESS) { - /* Move to next island and maybe next object */ - - if (goto_next_island(ssc)) { - StitchState *new_active_state = ssc->states[ssc->active_object_index]; - - /* active_state is the original active state */ - if (active_state != new_active_state) { - if (!stitch_process_data(ssc, active_state, scene, false)) { - stitch_cancel(C, op); - return OPERATOR_CANCELLED; - } - } - - if (!stitch_process_data(ssc, new_active_state, scene, false)) { - stitch_cancel(C, op); - return OPERATOR_CANCELLED; - } - } - break; - } - return OPERATOR_RUNNING_MODAL; - - case MKEY: - if (event->val == KM_PRESS) { - ssc->midpoints = !ssc->midpoints; - if (!stitch_process_data(ssc, active_state, scene, false)) { - stitch_cancel(C, op); - return OPERATOR_CANCELLED; - } - } - break; - - /* Select geometry */ - case RIGHTMOUSE: - if (!event->shift) { - stitch_cancel(C, op); - return OPERATOR_CANCELLED; - } - if (event->val == KM_PRESS) { - StitchState *selected_state = stitch_select(C, scene, event, ssc); - - if (selected_state && !stitch_process_data(ssc, selected_state, scene, false)) { - stitch_cancel(C, op); - return OPERATOR_CANCELLED; - } - break; - } - return OPERATOR_RUNNING_MODAL; - - /* snap islands on/off */ - case SKEY: - if (event->val == KM_PRESS) { - ssc->snap_islands = !ssc->snap_islands; - if (!stitch_process_data(ssc, active_state, scene, false)) { - stitch_cancel(C, op); - return OPERATOR_CANCELLED; - } - break; - } - else { - return OPERATOR_RUNNING_MODAL; - } - - /* switch between edge/vertex mode */ - case TABKEY: - if (event->val == KM_PRESS) { - stitch_switch_selection_mode_all(ssc); - - if (!stitch_process_data_all(ssc, scene, false)) { - stitch_cancel(C, op); - return OPERATOR_CANCELLED; - } - } - break; - - default: - return OPERATOR_RUNNING_MODAL; - } - - /* if updated settings, renew feedback message */ - stitch_update_header(ssc, C); - ED_region_tag_redraw(CTX_wm_region(C)); - - return OPERATOR_RUNNING_MODAL; + StitchStateContainer *ssc; + Scene *scene = CTX_data_scene(C); + + ssc = op->customdata; + StitchState *active_state = ssc->states[ssc->active_object_index]; + + switch (event->type) { + case MIDDLEMOUSE: + return OPERATOR_PASS_THROUGH; + + /* Cancel */ + case ESCKEY: + stitch_cancel(C, op); + return OPERATOR_CANCELLED; + + case LEFTMOUSE: + case PADENTER: + case RETKEY: + if (event->val == KM_PRESS) { + if (stitch_process_data(ssc, active_state, scene, true)) { + stitch_exit(C, op, 1); + return OPERATOR_FINISHED; + } + else { + stitch_cancel(C, op); + return OPERATOR_CANCELLED; + } + } + else { + return OPERATOR_PASS_THROUGH; + } + /* Increase limit */ + case PADPLUSKEY: + case WHEELUPMOUSE: + if (event->val == KM_PRESS && event->alt) { + ssc->limit_dist += 0.01f; + if (!stitch_process_data(ssc, active_state, scene, false)) { + stitch_cancel(C, op); + return OPERATOR_CANCELLED; + } + break; + } + else { + return OPERATOR_PASS_THROUGH; + } + /* Decrease limit */ + case PADMINUS: + case WHEELDOWNMOUSE: + if (event->val == KM_PRESS && event->alt) { + ssc->limit_dist -= 0.01f; + ssc->limit_dist = MAX2(0.01f, ssc->limit_dist); + if (!stitch_process_data(ssc, active_state, scene, false)) { + stitch_cancel(C, op); + return OPERATOR_CANCELLED; + } + break; + } + else { + return OPERATOR_PASS_THROUGH; + } + + /* Use Limit (Default off) */ + case LKEY: + if (event->val == KM_PRESS) { + ssc->use_limit = !ssc->use_limit; + if (!stitch_process_data(ssc, active_state, scene, false)) { + stitch_cancel(C, op); + return OPERATOR_CANCELLED; + } + break; + } + return OPERATOR_RUNNING_MODAL; + + case IKEY: + if (event->val == KM_PRESS) { + /* Move to next island and maybe next object */ + + if (goto_next_island(ssc)) { + StitchState *new_active_state = ssc->states[ssc->active_object_index]; + + /* active_state is the original active state */ + if (active_state != new_active_state) { + if (!stitch_process_data(ssc, active_state, scene, false)) { + stitch_cancel(C, op); + return OPERATOR_CANCELLED; + } + } + + if (!stitch_process_data(ssc, new_active_state, scene, false)) { + stitch_cancel(C, op); + return OPERATOR_CANCELLED; + } + } + break; + } + return OPERATOR_RUNNING_MODAL; + + case MKEY: + if (event->val == KM_PRESS) { + ssc->midpoints = !ssc->midpoints; + if (!stitch_process_data(ssc, active_state, scene, false)) { + stitch_cancel(C, op); + return OPERATOR_CANCELLED; + } + } + break; + + /* Select geometry */ + case RIGHTMOUSE: + if (!event->shift) { + stitch_cancel(C, op); + return OPERATOR_CANCELLED; + } + if (event->val == KM_PRESS) { + StitchState *selected_state = stitch_select(C, scene, event, ssc); + + if (selected_state && !stitch_process_data(ssc, selected_state, scene, false)) { + stitch_cancel(C, op); + return OPERATOR_CANCELLED; + } + break; + } + return OPERATOR_RUNNING_MODAL; + + /* snap islands on/off */ + case SKEY: + if (event->val == KM_PRESS) { + ssc->snap_islands = !ssc->snap_islands; + if (!stitch_process_data(ssc, active_state, scene, false)) { + stitch_cancel(C, op); + return OPERATOR_CANCELLED; + } + break; + } + else { + return OPERATOR_RUNNING_MODAL; + } + + /* switch between edge/vertex mode */ + case TABKEY: + if (event->val == KM_PRESS) { + stitch_switch_selection_mode_all(ssc); + + if (!stitch_process_data_all(ssc, scene, false)) { + stitch_cancel(C, op); + return OPERATOR_CANCELLED; + } + } + break; + + default: + return OPERATOR_RUNNING_MODAL; + } + + /* if updated settings, renew feedback message */ + stitch_update_header(ssc, C); + ED_region_tag_redraw(CTX_wm_region(C)); + + return OPERATOR_RUNNING_MODAL; } void UV_OT_stitch(wmOperatorType *ot) { - PropertyRNA *prop; - - static const EnumPropertyItem stitch_modes[] = { - {STITCH_VERT, "VERTEX", 0, "Vertex", ""}, - {STITCH_EDGE, "EDGE", 0, "Edge", ""}, - {0, NULL, 0, NULL, NULL}, - }; - - /* identifiers */ - ot->name = "Stitch"; - ot->description = "Stitch selected UV vertices by proximity"; - ot->idname = "UV_OT_stitch"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* api callbacks */ - ot->invoke = stitch_invoke; - ot->modal = stitch_modal; - ot->exec = stitch_exec; - ot->cancel = stitch_cancel; - ot->poll = ED_operator_uvedit; - - /* properties */ - RNA_def_boolean(ot->srna, "use_limit", 0, "Use Limit", "Stitch UVs within a specified limit distance"); - RNA_def_boolean(ot->srna, "snap_islands", 1, "Snap Islands", - "Snap islands together (on edge stitch mode, rotates the islands too)"); - - RNA_def_float(ot->srna, "limit", 0.01f, 0.0f, FLT_MAX, "Limit", - "Limit distance in normalized coordinates", 0.0, FLT_MAX); - RNA_def_int(ot->srna, "static_island", 0, 0, INT_MAX, "Static Island", - "Island that stays in place when stitching islands", 0, INT_MAX); - RNA_def_int(ot->srna, "active_object_index", 0, 0, INT_MAX, "Active Object", - "Index of the active object", 0, INT_MAX); - RNA_def_boolean(ot->srna, "midpoint_snap", 0, "Snap At Midpoint", - "UVs are stitched at midpoint instead of at static island"); - RNA_def_boolean(ot->srna, "clear_seams", 1, "Clear Seams", - "Clear seams of stitched edges"); - RNA_def_enum(ot->srna, "mode", stitch_modes, STITCH_VERT, "Operation Mode", - "Use vertex or edge stitching"); - prop = RNA_def_enum(ot->srna, "stored_mode", stitch_modes, STITCH_VERT, "Stored Operation Mode", - "Use vertex or edge stitching"); - RNA_def_property_flag(prop, PROP_HIDDEN); - prop = RNA_def_collection_runtime(ot->srna, "selection", &RNA_SelectedUvElement, "Selection", ""); - /* Selection should not be editable or viewed in toolbar */ - RNA_def_property_flag(prop, PROP_HIDDEN); - - /* test should not be editable or viewed in toolbar */ - prop = RNA_def_int_array(ot->srna, "objects_selection_count", 1, NULL, 0, INT_MAX, "Objects Selection Count", - "", 0, INT_MAX); - RNA_def_property_array(prop, 6); - RNA_def_property_flag(prop, PROP_HIDDEN); + PropertyRNA *prop; + + static const EnumPropertyItem stitch_modes[] = { + {STITCH_VERT, "VERTEX", 0, "Vertex", ""}, + {STITCH_EDGE, "EDGE", 0, "Edge", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Stitch"; + ot->description = "Stitch selected UV vertices by proximity"; + ot->idname = "UV_OT_stitch"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* api callbacks */ + ot->invoke = stitch_invoke; + ot->modal = stitch_modal; + ot->exec = stitch_exec; + ot->cancel = stitch_cancel; + ot->poll = ED_operator_uvedit; + + /* properties */ + RNA_def_boolean( + ot->srna, "use_limit", 0, "Use Limit", "Stitch UVs within a specified limit distance"); + RNA_def_boolean(ot->srna, + "snap_islands", + 1, + "Snap Islands", + "Snap islands together (on edge stitch mode, rotates the islands too)"); + + RNA_def_float(ot->srna, + "limit", + 0.01f, + 0.0f, + FLT_MAX, + "Limit", + "Limit distance in normalized coordinates", + 0.0, + FLT_MAX); + RNA_def_int(ot->srna, + "static_island", + 0, + 0, + INT_MAX, + "Static Island", + "Island that stays in place when stitching islands", + 0, + INT_MAX); + RNA_def_int(ot->srna, + "active_object_index", + 0, + 0, + INT_MAX, + "Active Object", + "Index of the active object", + 0, + INT_MAX); + RNA_def_boolean(ot->srna, + "midpoint_snap", + 0, + "Snap At Midpoint", + "UVs are stitched at midpoint instead of at static island"); + RNA_def_boolean(ot->srna, "clear_seams", 1, "Clear Seams", "Clear seams of stitched edges"); + RNA_def_enum(ot->srna, + "mode", + stitch_modes, + STITCH_VERT, + "Operation Mode", + "Use vertex or edge stitching"); + prop = RNA_def_enum(ot->srna, + "stored_mode", + stitch_modes, + STITCH_VERT, + "Stored Operation Mode", + "Use vertex or edge stitching"); + RNA_def_property_flag(prop, PROP_HIDDEN); + prop = RNA_def_collection_runtime( + ot->srna, "selection", &RNA_SelectedUvElement, "Selection", ""); + /* Selection should not be editable or viewed in toolbar */ + RNA_def_property_flag(prop, PROP_HIDDEN); + + /* test should not be editable or viewed in toolbar */ + prop = RNA_def_int_array(ot->srna, + "objects_selection_count", + 1, + NULL, + 0, + INT_MAX, + "Objects Selection Count", + "", + 0, + INT_MAX); + RNA_def_property_array(prop, 6); + RNA_def_property_flag(prop, PROP_HIDDEN); } |