Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/BKE_mesh.h2
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c14
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c1399
3 files changed, 986 insertions, 429 deletions
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index e53d0efffbd..3fc1b7d6136 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -229,8 +229,6 @@ typedef struct UvElement {
/* Next UvElement corresponding to same vertex */
struct UvElement *next;
/* Face the element belongs to */
- struct BMFace *face;
- /* Index in the editFace of the uv */
struct BMLoop *l;
/* index in loop. */
unsigned short tfindex;
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index cbb7262beb2..b1094c75f27 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -876,7 +876,6 @@ UvElementMap *EDBM_uv_element_map_create(BMEditMesh *em, int selected, int do_is
if (!selected || ((!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) && BM_elem_flag_test(efa, BM_ELEM_SELECT))) {
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
buf->l = l;
- buf->face = efa;
buf->separate = 0;
buf->island = INVALID_ISLAND;
buf->tfindex = i;
@@ -948,7 +947,7 @@ UvElementMap *EDBM_uv_element_map_create(BMEditMesh *em, int selected, int do_is
for (i = 0; i < totuv; i++) {
if (element_map->buf[i].island == INVALID_ISLAND) {
element_map->buf[i].island = nislands;
- stack[0] = element_map->buf[i].face;
+ stack[0] = element_map->buf[i].l->f;
island_number[BM_elem_index_get(stack[0])] = nislands;
stacksize = 1;
@@ -962,12 +961,11 @@ UvElementMap *EDBM_uv_element_map_create(BMEditMesh *em, int selected, int do_is
if (element->separate)
initelement = element;
- if (element->face == efa) {
+ if (element->l->f == efa) {
/* found the uv corresponding to our face and vertex. Now fill it to the buffer */
element->island = nislands;
map[element - element_map->buf] = islandbufsize;
islandbuf[islandbufsize].l = element->l;
- islandbuf[islandbufsize].face = element->face;
islandbuf[islandbufsize].separate = element->separate;
islandbuf[islandbufsize].tfindex = element->tfindex;
islandbuf[islandbufsize].island = nislands;
@@ -977,9 +975,9 @@ UvElementMap *EDBM_uv_element_map_create(BMEditMesh *em, int selected, int do_is
if (element->separate && element != initelement)
break;
- if (island_number[BM_elem_index_get(element->face)] == INVALID_ISLAND) {
- stack[stacksize++] = element->face;
- island_number[BM_elem_index_get(element->face)] = nislands;
+ if (island_number[BM_elem_index_get(element->l->f)] == INVALID_ISLAND) {
+ stack[stacksize++] = element->l->f;
+ island_number[BM_elem_index_get(element->l->f)] = nislands;
}
}
break;
@@ -1060,7 +1058,7 @@ UvElement *ED_uv_element_get(UvElementMap *map, BMFace *efa, BMLoop *l)
element = map->vert[BM_elem_index_get(l->v)];
for (; element; element = element->next)
- if (element->face == efa)
+ if (element->l->f == efa)
return element;
return NULL;
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index 9c99eb196c2..280b6f0703d 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -72,24 +72,24 @@
/* ********************** smart stitch operator *********************** */
-/* object that stores display data for previewing before accepting stitching */
+/* 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 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;
@@ -98,85 +98,96 @@ struct IslandStitchData;
/* This is a straightforward implementation, count the uv's in the island that will move and take the mean displacement/rotation and apply it to all
* 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 translation[2];
- /* Used for rotation, the island will rotate around this point */
- float medianPoint[2];
- int numOfElements;
- int num_rot_elements;
- /* 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 */
- char use_edge_rotation;
+ /* rotation can be used only for edges, for vertices there is no such notion */
+ float rotation;
+ float translation[2];
+ /* Used for rotation, the island will rotate around this point */
+ float medianPoint[2];
+ int numOfElements;
+ int num_rot_elements;
+ /* 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 */
+ char 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) */
- char flag;
- /* element that guarantees element->face has the face on element->tfindex and element->tfindex+1 is the second uv */
- UvElement *element;
+ /* 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 {
- /* use limit flag */
- char use_limit;
- /* limit to operator, same as original operator */
- float limit_dist;
- /* snap uv islands together during stitching */
- char snap_islands;
- /* stich at midpoints or at islands */
- char midpoints;
- /* editmesh, cached for use in modal handler */
- BMEditMesh *em;
- /* clear seams of stitched edges after stitch */
- char clear_seams;
- /* 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;
-
- /* count of separate uvs and edges */
- int total_boundary_edges;
- int total_separate_uvs;
- /* hold selection related information */
- UvElement **selection_stack;
- int selection_size;
- /* island that stays in place */
- int static_island;
- /* store number of primitives per face so that we can allocate the active island buffer later */
- unsigned int *tris_per_island;
-
- void *draw_handle;
+ /* use limit flag */
+ char use_limit;
+ /* limit to operator, same as original operator */
+ float limit_dist;
+ /* snap uv islands together during stitching */
+ char snap_islands;
+ /* stich at midpoints or at islands */
+ char midpoints;
+ /* editmesh, cached for use in modal handler */
+ BMEditMesh *em;
+ /* clear seams of stitched edges after stitch */
+ char clear_seams;
+ /* 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;
+
+ /* count of separate uvs and edges */
+ int total_separate_edges;
+ int total_separate_uvs;
+ /* hold selection related information */
+ void **selection_stack;
+ int selection_size;
+ /* island that stays in place */
+ int static_island;
+ /* store number of primitives per face so that we can allocate the active island buffer later */
+ unsigned int *tris_per_island;
+
+ /* vert or edge mode used for stitching */
+ char mode;
+ /* handle for drawing */
+ void *draw_handle;
+ /* preview data */
+ StitchPreviewer *stitch_preview;
} StitchState;
typedef struct PreviewPosition {
- int data_position;
- int polycount_position;
+ int data_position;
+ int polycount_position;
} PreviewPosition;
/*
- * defines for UvElement flags
+ * defines for UvElement/UcEdge flags
*/
#define STITCH_SELECTED 1
#define STITCH_STITCHABLE 2
@@ -186,83 +197,79 @@ typedef struct PreviewPosition {
#define STITCH_NO_PREVIEW -1
-/* previewer stuff (see uvedit_intern.h for more info) */
-static StitchPreviewer *_stitch_preview;
+enum StitchModes {
+ STITCH_VERT,
+ STITCH_EDGE
+};
/* constructor */
static StitchPreviewer *stitch_preview_init(void)
{
- _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;
+ 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->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(void)
+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) {
+ 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->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_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->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;
+ if (stitch_preview->static_tris) {
+ MEM_freeN(stitch_preview->static_tris);
+ stitch_preview->static_tris = NULL;
}
-
- MEM_freeN(_stitch_preview);
- _stitch_preview = NULL;
+ MEM_freeN(stitch_preview);
}
}
-
-/* "getter method" */
-static StitchPreviewer *uv_get_stitch_previewer(void)
-{
- return _stitch_preview;
-}
-
#define HEADER_LENGTH 256
/* This function updates the header of the UV editor when the stitch tool updates its settings */
-static void stitch_update_header(StitchState *stitch_state, bContext *C)
+static void stitch_update_header(StitchState *state, bContext *C)
{
- static char str[] = "(S)nap %s, (M)idpoints %s, (L)imit %.2f (Alt Wheel adjust) %s, Switch (I)sland, shift select vertices";
+ static char str[] = "Mode(TAB) %s, (S)nap %s, (M)idpoints %s, (L)imit %.2f (Alt Wheel adjust) %s, Switch (I)sland, shift select vertices";
char msg[HEADER_LENGTH];
ScrArea *sa = CTX_wm_area(C);
if (sa) {
BLI_snprintf(msg, HEADER_LENGTH, str,
- stitch_state->snap_islands ? "On" : "Off",
- stitch_state->midpoints ? "On" : "Off",
- stitch_state->limit_dist,
- stitch_state->use_limit ? "On" : "Off");
+ state->mode == STITCH_VERT ? "Vertex" : "Edge",
+ state->snap_islands ? "On" : "Off",
+ state->midpoints ? "On" : "Off",
+ state->limit_dist,
+ state->use_limit ? "On" : "Off");
ED_area_headerprint(sa, msg);
}
@@ -292,30 +299,29 @@ static void stitch_uv_rotate(float rotation, float medianPoint[2], float uv[2])
uv[1] = uv_rotation_result[1] + medianPoint[1];
}
+/* check if two uvelements are stitchable. This should only operate on -different- separate UvElements */
static int stitch_check_uvs_stitchable(UvElement *element, UvElement *element_iter, StitchState *state)
{
float limit;
- int do_limit;
if (element_iter == element) {
return 0;
}
limit = state->limit_dist;
- do_limit = state->use_limit;
- if (do_limit) {
- MLoopUV *luv_orig, *luv_iter;
- BMLoop *l_orig, *l_iter;
+ if (state->use_limit) {
+ MLoopUV *luv, *luv_iter;
+ BMLoop *l;
- l_orig = element->l;
- luv_orig = CustomData_bmesh_get(&state->em->bm->ldata, l_orig->head.data, CD_MLOOPUV);
- l_iter = element_iter->l;
- luv_iter = CustomData_bmesh_get(&state->em->bm->ldata, l_iter->head.data, CD_MLOOPUV);
+ l = element->l;
+ luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+ l = element_iter->l;
+ luv_iter = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
- if (fabsf(luv_orig->uv[0] - luv_iter->uv[0]) < limit &&
- fabsf(luv_orig->uv[1] - luv_iter->uv[1]) < limit)
+ if (fabsf(luv->uv[0] - luv_iter->uv[0]) < limit &&
+ fabsf(luv->uv[1] - luv_iter->uv[1]) < limit)
{
return 1;
}
@@ -328,6 +334,46 @@ static int stitch_check_uvs_stitchable(UvElement *element, UvElement *element_it
}
}
+static int stitch_check_edges_stitchable(UvEdge *edge, UvEdge *edge_iter, StitchState *state)
+{
+ float limit;
+
+ if (edge_iter == edge) {
+ return 0;
+ }
+
+ limit = state->limit_dist;
+
+ if(state->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(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+ l = state->uvs[edge_iter->uv1]->l;
+ luv_iter1 = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+ l = state->uvs[edge->uv2]->l;
+ luv_orig2 = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+ l = state->uvs[edge_iter->uv2]->l;
+ luv_iter2 = CustomData_bmesh_get(&state->em->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 int stitch_check_uvs_state_stitchable(UvElement *element, UvElement *element_iter, StitchState *state)
{
@@ -341,6 +387,17 @@ static int stitch_check_uvs_state_stitchable(UvElement *element, UvElement *elem
}
+static int stitch_check_edges_state_stitchable(UvEdge *edge, UvEdge *edge_iter, StitchState *state)
+{
+ if ((state->snap_islands && edge->element->island == edge_iter->element->island) ||
+ (!state->midpoints && edge->element->island == edge_iter->element->island))
+ {
+ return 0;
+ }
+
+ return stitch_check_edges_stitchable(edge, edge_iter, state);
+}
+
/* calculate snapping for islands */
static void stitch_calculate_island_snapping(StitchState *state, PreviewPosition *preview_position, StitchPreviewer *preview, IslandStitchData *island_stitch_data, int final)
{
@@ -378,7 +435,7 @@ static void stitch_calculate_island_snapping(StitchState *state, PreviewPosition
}
else {
- int face_preview_pos = preview_position[BM_elem_index_get(element->face)].data_position;
+ int face_preview_pos = preview_position[BM_elem_index_get(element->l->f)].data_position;
stitch_uv_rotate(island_stitch_data[i].rotation, island_stitch_data[i].medianPoint,
preview->preview_polys + face_preview_pos + 2 * element->tfindex);
@@ -414,9 +471,13 @@ static void stitch_island_calculate_edge_rotation(UvEdge *edge, StitchState *sta
l2 = element2->l;
luv2 = CustomData_bmesh_get(&state->em->bm->ldata, l2->head.data, CD_MLOOPUV);
- index1 = uvfinal_map[element1 - state->element_map->buf];
- index2 = uvfinal_map[element2 - state->element_map->buf];
-
+ if (state->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];
@@ -461,7 +522,10 @@ static void stitch_island_calculate_vert_rotation(UvElement *element, StitchStat
if (element_iter->separate && stitch_check_uvs_state_stitchable(element, element_iter, state)) {
int index_tmp1, index_tmp2;
float normal[2];
- /* easily possible*/
+
+ /* only calculate rotation against static island uv verts */
+ if(!state->midpoints && element_iter->island != state->static_island)
+ continue;
index_tmp1 = element_iter - state->element_map->buf;
index_tmp1 = state->map[index_tmp1];
@@ -482,34 +546,112 @@ static void stitch_island_calculate_vert_rotation(UvElement *element, StitchStat
}
-static void stitch_state_delete(StitchState *stitch_state)
+static void state_delete(StitchState *state)
{
- if (stitch_state) {
- if (stitch_state->element_map) {
- EDBM_uv_element_map_free(stitch_state->element_map);
+ if (state) {
+ if (state->element_map) {
+ EDBM_uv_element_map_free(state->element_map);
}
- if (stitch_state->uvs) {
- MEM_freeN(stitch_state->uvs);
+ if (state->uvs) {
+ MEM_freeN(state->uvs);
}
- if (stitch_state->selection_stack) {
- MEM_freeN(stitch_state->selection_stack);
+ if (state->selection_stack) {
+ MEM_freeN(state->selection_stack);
}
- if (stitch_state->tris_per_island) {
- MEM_freeN(stitch_state->tris_per_island);
+ if (state->tris_per_island) {
+ MEM_freeN(state->tris_per_island);
}
- if (stitch_state->map) {
- MEM_freeN(stitch_state->map);
+ if (state->map) {
+ MEM_freeN(state->map);
}
- if (stitch_state->normals) {
- MEM_freeN(stitch_state->normals);
+ if (state->normals) {
+ MEM_freeN(state->normals);
}
- if (stitch_state->edges) {
- MEM_freeN(stitch_state->edges);
+ if (state->edges) {
+ MEM_freeN(state->edges);
}
- MEM_freeN(stitch_state);
+ 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 stitch_uv_edge_generate_linked_edges(GHash *edge_hash, StitchState *state)
+{
+ UvEdge *edges = state->edges;
+ 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 = ED_uv_element_get(element_map, iter1->l->f, iter1->l->next);
+ else if(BM_elem_index_get(iter1->l->prev->v) == elemindex2)
+ iter2 = ED_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];
+
+ /* make certain we do not have the same edge! */
+ if(state->uvs[index2] != element2 && state->uvs[index1] != element1) {
+ UvEdge edgetmp;
+ UvEdge *edge2;
+
+
+ /* make sure the indices are well behaved */
+ if(index1 < index2) {
+ edgetmp.uv1 = index1;
+ edgetmp.uv2 = index2;
+ } else {
+ edgetmp.uv1 = index2;
+ edgetmp.uv2 = index1;
+ }
+
+ /* get the edge from the hash */
+ edge2 = BLI_ghash_lookup(edge_hash, &edgetmp);
+
+ /* 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. */
@@ -526,9 +668,6 @@ static void determine_uv_stitchability(UvElement *element, StitchState *state, I
for (; element_iter; element_iter = element_iter->next) {
if (element_iter->separate) {
- if (element_iter == element) {
- continue;
- }
if (stitch_check_uvs_stitchable(element, element_iter, state)) {
island_stitch_data[element_iter->island].stitchableCandidate = 1;
island_stitch_data[element->island].stitchableCandidate = 1;
@@ -538,6 +677,19 @@ static void determine_uv_stitchability(UvElement *element, StitchState *state, I
}
}
+static void determine_uv_edge_stitchability(UvEdge *edge, 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, 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)
@@ -555,7 +707,7 @@ static void stitch_set_face_preview_buffer_position(BMFace *efa, StitchPreviewer
/* setup face preview for all coincident uvs and their faces */
static void stitch_setup_face_preview_for_uv_group(UvElement *element, StitchState *state, IslandStitchData *island_stitch_data,
PreviewPosition *preview_position) {
- StitchPreviewer *preview = uv_get_stitch_previewer();
+ StitchPreviewer *preview = state->stitch_preview;
/* static island does not change so returning immediately */
if (state->snap_islands && !state->midpoints && state->static_island == element->island)
@@ -566,17 +718,17 @@ static void stitch_setup_face_preview_for_uv_group(UvElement *element, StitchSta
}
do {
- stitch_set_face_preview_buffer_position(element->face, preview, preview_position);
+ 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_stichability(UvElement *element, StitchState *state, IslandStitchData *island_stitch_data,
+static void stitch_validate_uv_stichability(UvElement *element, StitchState *state, IslandStitchData *island_stitch_data,
PreviewPosition *preview_position) {
UvElement *element_iter;
- StitchPreviewer *preview;
+ StitchPreviewer *preview = state->stitch_preview;
int vert_index;
BMLoop *l;
@@ -584,7 +736,6 @@ static void stitch_validate_stichability(UvElement *element, StitchState *state,
vert_index = BM_elem_index_get(l->v);
- preview = uv_get_stitch_previewer();
element_iter = state->element_map->vert[vert_index];
for (; element_iter; element_iter = element_iter->next) {
@@ -608,6 +759,72 @@ static void stitch_validate_stichability(UvElement *element, StitchState *state,
}
}
+
+static void stitch_validate_edge_stichability(UvEdge *edge, StitchState *state, IslandStitchData *island_stitch_data,
+ PreviewPosition *preview_position) {
+ UvEdge *edge_iter = edge->first;
+ StitchPreviewer *preview = state->stitch_preview;
+
+ for (; edge_iter; edge_iter = edge_iter->next) {
+ if (edge_iter == edge)
+ continue;
+ if (stitch_check_edges_state_stitchable(edge, edge_iter, state)) {
+ if ((edge_iter->element->island == state->static_island) || (edge->element->island == state->static_island)) {
+ edge->flag |= STITCH_STITCHABLE;
+ preview->num_stitchable++;
+ stitch_setup_face_preview_for_uv_group(state->uvs[edge->uv1], state, island_stitch_data, preview_position);
+ stitch_setup_face_preview_for_uv_group(state->uvs[edge->uv2], 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 (UvElement *element, int index, PreviewPosition *preview_position, UVVertAverage *final_position, StitchState *state, char final, Scene* scene)
+{
+ StitchPreviewer *preview = state->stitch_preview;
+
+ 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(&state->em->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);
+ }
+ 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->tfindex,
+ final_position[index].uv);
+ }
+ }
+
+ /* end of calculations, keep only the selection flag */
+ if ( (!state->snap_islands) || ((!state->midpoints) && (element_iter->island == state->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(StitchState *state, Scene *scene, int final)
{
@@ -618,6 +835,7 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
BMFace *efa;
BMIter iter;
UVVertAverage *final_position;
+
char stitch_midpoints = state->midpoints;
/* used to map uv indices to uvaverage indices for selection */
unsigned int *uvfinal_map;
@@ -625,8 +843,8 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
PreviewPosition *preview_position;
/* cleanup previous preview */
- stitch_preview_delete();
- preview = stitch_preview_init();
+ stitch_preview_delete(state->stitch_preview);
+ preview = state->stitch_preview = stitch_preview_init();
if (preview == NULL)
return 0;
@@ -649,8 +867,13 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
*****************************************/
for (i = 0; i < state->selection_size; i++) {
- UvElement *element = state->selection_stack[i];
- determine_uv_stitchability(element, state, island_stitch_data);
+ if(state->mode == STITCH_VERT) {
+ UvElement *element = (UvElement *)state->selection_stack[i];
+ determine_uv_stitchability(element, state, island_stitch_data);
+ } else {
+ UvEdge *edge = (UvEdge *)state->selection_stack[i];
+ determine_uv_edge_stitchability(edge, state, island_stitch_data);
+ }
}
/* set static island to one that is added for preview */
@@ -664,14 +887,25 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
}
for (i = 0; i < state->selection_size; i++) {
- UvElement *element = state->selection_stack[i];
- if (element->flag & STITCH_STITCHABLE_CANDIDATE) {
- element->flag &= ~STITCH_STITCHABLE_CANDIDATE;
- stitch_validate_stichability(element, state, island_stitch_data, preview_position);
- }
- else {
- /* add to preview for unstitchable */
- preview->num_unstitchable++;
+ if(state->mode == STITCH_VERT) {
+ UvElement *element = (UvElement *)state->selection_stack[i];
+ if (element->flag & STITCH_STITCHABLE_CANDIDATE) {
+ element->flag &= ~STITCH_STITCHABLE_CANDIDATE;
+ stitch_validate_uv_stichability(element, 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_stichability(edge, state, island_stitch_data, preview_position);
+ }
+ else {
+ preview->num_unstitchable++;
+ }
}
}
@@ -686,7 +920,7 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
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->face, preview, preview_position);
+ stitch_set_face_preview_buffer_position(element->l->f, preview, preview_position);
}
}
}
@@ -701,11 +935,12 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
MLoopUV *luv;
unsigned int buffer_index = 0;
int stitchBufferIndex = 0, unstitchBufferIndex = 0;
+ int preview_size = (state->mode == STITCH_VERT) ? 2 : 4;
/* initialize the preview buffers */
preview->preview_polys = (float *)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->preview_stitchable = (float *)MEM_mallocN(preview->num_stitchable * sizeof(float) * 2, "stitch_preview_stichable_data");
- preview->preview_unstitchable = (float *)MEM_mallocN(preview->num_unstitchable * sizeof(float) * 2, "stitch_preview_unstichable_data");
+ preview->preview_stitchable = (float *)MEM_mallocN(preview->num_stitchable * sizeof(float) * preview_size, "stitch_preview_stichable_data");
+ preview->preview_unstitchable = (float *)MEM_mallocN(preview->num_unstitchable * sizeof(float) * preview_size, "stitch_preview_unstichable_data");
preview->static_tris = (float *)MEM_mallocN(state->tris_per_island[state->static_island] * sizeof(float) * 6, "static_island_preview_tris");
@@ -715,7 +950,7 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
return 0;
}
- /* copy data from MTFaces to the preview display buffers */
+ /* copy data from MLoopUVs to the preview display buffers */
BM_ITER_MESH (efa, &iter, state->em->bm, BM_FACES_OF_MESH) {
/* just to test if face was added for processing. uvs of inselected vertices will return NULL */
UvElement *element = ED_uv_element_get(state->element_map, efa, BM_FACE_FIRST_LOOP(efa));
@@ -757,22 +992,54 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
}
/* fill the appropriate preview buffers */
- 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(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+ if(state->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(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
- copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 2], luv->uv);
+ copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 2], luv->uv);
- stitchBufferIndex++;
+ stitchBufferIndex++;
+ }
+ else if (element->flag & STITCH_SELECTED) {
+ l = element->l;
+ luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+
+ copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 2], luv->uv);
+ unstitchBufferIndex++;
+ }
}
- else if (element->flag & STITCH_SELECTED) {
- l = element->l;
- luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+ } 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(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+ copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 4], luv->uv);
- copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 2], luv->uv);
- unstitchBufferIndex++;
+ l = element2->l;
+ luv = CustomData_bmesh_get(&state->em->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(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+ copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 4], luv->uv);
+
+ l = element2->l;
+ luv = CustomData_bmesh_get(&state->em->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);
+ }
}
}
}
@@ -781,141 +1048,215 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
* Here we calculate the final coordinates of the uvs *
******************************************************/
- 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");
+ if (state->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++) {
- UvElement *element = state->selection_stack[i];
- if (element->flag & STITCH_STITCHABLE) {
- BMLoop *l;
- MLoopUV *luv;
- UvElement *element_iter;
+ if (state->mode == STITCH_VERT) {
+ UvElement *element = state->selection_stack[i];
- l = element->l;
- luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+ if (element->flag & STITCH_STITCHABLE) {
+ BMLoop *l;
+ MLoopUV *luv;
+ UvElement *element_iter;
+ l = element->l;
+ luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
- uvfinal_map[element - state->element_map->buf] = i;
+ uvfinal_map[element - state->element_map->buf] = i;
- copy_v2_v2(final_position[i].uv, luv->uv);
- final_position[i].count = 1;
+ copy_v2_v2(final_position[i].uv, luv->uv);
+ final_position[i].count = 1;
- if (state->snap_islands && element->island == state->static_island && !stitch_midpoints)
- continue;
+ if (state->snap_islands && element->island == state->static_island && !stitch_midpoints)
+ continue;
- element_iter = state->element_map->vert[BM_elem_index_get(l->v)];
+ 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, state)) {
+ l = element_iter->l;
+ luv = CustomData_bmesh_get(&state->em->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 == state->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];
- for ( ; element_iter; element_iter = element_iter->next) {
- if (element_iter->separate) {
- if (stitch_check_uvs_state_stitchable(element, element_iter, state)) {
- l = element_iter->l;
- luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
- if (stitch_midpoints) {
- add_v2_v2(final_position[i].uv, luv->uv);
- final_position[i].count++;
+ if (edge->flag & STITCH_STITCHABLE) {
+ MLoopUV *luv2, *luv1;
+ BMLoop *l;
+ UvEdge *edge_iter;
+
+ l = state->uvs[edge->uv1]->l;
+ luv1 = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+ l = state->uvs[edge->uv2]->l;
+ luv2 = CustomData_bmesh_get(&state->em->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 (state->snap_islands && edge->element->island == state->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, state)) {
+ l = state->uvs[edge_iter->uv1]->l;
+ luv1 = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+ l = state->uvs[edge_iter->uv2]->l;
+ luv2 = CustomData_bmesh_get(&state->em->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 (element_iter->island == state->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);
+ else if (edge_iter->element->island == state->static_island) {
+ copy_v2_v2(final_position[edge->uv1].uv, luv1->uv);
+ copy_v2_v2(final_position[edge->uv2].uv, luv2->uv);
}
}
}
}
}
- if (stitch_midpoints) {
- 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 (state->snap_islands) {
- for (i = 0; i < state->selection_size; i++) {
- UvElement *element = state->selection_stack[i];
- if (element->flag & STITCH_STITCHABLE) {
- BMLoop *l;
- MLoopUV *luv;
+ if (state->mode == STITCH_VERT) {
+ for (i = 0; i < state->selection_size; i++) {
+ UvElement *element = state->selection_stack[i];
- l = element->l;
- luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+ if (element->flag & STITCH_STITCHABLE) {
+ BMLoop *l;
+ MLoopUV *luv;
- /* 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++;
- }
- }
+ l = element->l;
+ luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
- /* only calculate rotation when an edge has been fully selected */
- for (i = 0; i < state->total_boundary_edges; i++) {
- UvEdge *edge = state->edges + i;
- if ((state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) && (state->uvs[edge->uv2]->flag & STITCH_STITCHABLE)) {
- stitch_island_calculate_edge_rotation(edge, state, final_position, uvfinal_map, island_stitch_data);
- island_stitch_data[state->uvs[edge->uv1]->island].use_edge_rotation = TRUE;
+ /* 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++;
+ }
}
- }
- /* clear seams of stitched edges */
- if (final && state->clear_seams) {
- for (i = 0; i < state->total_boundary_edges; i++) {
+ /* 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 ((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);
+ 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, state, final_position, uvfinal_map, island_stitch_data);
+ island_stitch_data[state->uvs[edge->uv1]->island].use_edge_rotation = TRUE;
+ }
}
- }
- 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, state, island_stitch_data);
+ /* clear seams of stitched edges */
+ if (final && state->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, state, island_stitch_data);
+ }
+ }
+ }
+ } else {
+ for (i = 0; i < state->total_separate_uvs; i++) {
+ UvElement *element = state->uvs[i];
- /* third pass, propagate changes to coincident uvs */
- for (i = 0; i < state->selection_size; i++) {
- UvElement *element = state->selection_stack[i];
- if (element->flag & STITCH_STITCHABLE) {
- UvElement *element_iter = element;
- /* propagate to coincident uvs */
- do {
- BMLoop *l;
- MLoopUV *luv;
+ if (stitch_midpoints) {
+ final_position[i].uv[0] /= final_position[i].count;
+ final_position[i].uv[1] /= final_position[i].count;
+ }
- l = element_iter->l;
- luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
+ if (element->flag & STITCH_STITCHABLE) {
+ BMLoop *l;
+ MLoopUV *luv;
- element_iter->flag |= STITCH_PROCESSED;
- /* either flush to preview or to the MTFace, if final */
- if (final) {
- copy_v2_v2(luv->uv, final_position[i].uv);
+ l = element->l;
+ luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV);
- uvedit_uv_select_enable(state->em, scene, l, FALSE);
+ /* 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++;
}
- else {
- int face_preview_pos = preview_position[BM_elem_index_get(element_iter->face)].data_position;
- if (face_preview_pos != STITCH_NO_PREVIEW) {
- copy_v2_v2(preview->preview_polys + face_preview_pos + 2 * element_iter->tfindex,
- final_position[i].uv);
- }
+ }
+
+ 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, state, final_position, NULL, island_stitch_data);
+ island_stitch_data[state->uvs[edge->uv1]->island].use_edge_rotation = TRUE;
}
+ }
- /* end of calculations, keep only the selection flag */
- if ( (!state->snap_islands) || ((!stitch_midpoints) && (element_iter->island == state->static_island))) {
- element_iter->flag &= STITCH_SELECTED;
+ /* clear seams of stitched edges */
+ if (final && state->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 (state->mode == STITCH_VERT) {
+ UvElement *element = state->selection_stack[i];
+
+ stitch_propagate_uv_final_position (element, i, preview_position, final_position, state, final, scene);
+ } else {
+ UvEdge *edge = state->selection_stack[i];
+
+ stitch_propagate_uv_final_position (state->uvs[edge->uv1], edge->uv1, preview_position, final_position, state, final, scene);
+ stitch_propagate_uv_final_position (state->uvs[edge->uv2], edge->uv2, preview_position, final_position, state, final, scene);
- element_iter = element_iter->next;
- } while (element_iter && !element_iter->separate);
+ edge->flag &= (STITCH_SELECTED | STITCH_BOUNDARY);
}
}
@@ -925,7 +1266,9 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
}
MEM_freeN(final_position);
- MEM_freeN(uvfinal_map);
+ if (state->mode == STITCH_VERT) {
+ MEM_freeN(uvfinal_map);
+ }
MEM_freeN(island_stitch_data);
MEM_freeN(preview_position);
@@ -937,8 +1280,8 @@ static unsigned int uv_edge_hash(const void *key)
{
UvEdge *edge = (UvEdge *)key;
return
- BLI_ghashutil_inthash(SET_INT_IN_POINTER(edge->uv2)) +
- BLI_ghashutil_inthash(SET_INT_IN_POINTER(edge->uv1));
+ BLI_ghashutil_inthash(SET_INT_IN_POINTER(edge->uv2)) +
+ BLI_ghashutil_inthash(SET_INT_IN_POINTER(edge->uv1));
}
static int uv_edge_compare(const void *a, const void *b)
@@ -952,13 +1295,41 @@ static int uv_edge_compare(const void *a, const void *b)
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;
+ }
+ }
+}
+
/* Select all common uvs */
static void stitch_select_uv(UvElement *element, StitchState *state, int always_select)
{
BMLoop *l;
UvElement *element_iter;
- UvElement **selection_stack = state->selection_stack;
+ UvElement **selection_stack = (UvElement **)state->selection_stack;
l = element->l;
@@ -989,6 +1360,54 @@ static void stitch_select_uv(UvElement *element, StitchState *state, int always_
}
}
+static void stitch_switch_selection_mode(StitchState *state)
+{
+ void **old_selection_stack = state->selection_stack;
+ int old_selection_size = state->selection_size;
+ state->selection_size = 0;
+
+ if (state->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;
+ }
+ state->mode = STITCH_EDGE;
+ } 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;
+ }
+ state->mode = STITCH_VERT;
+ }
+ MEM_freeN(old_selection_stack);
+}
+
static void stitch_calculate_edge_normal(BMEditMesh *em, UvEdge *edge, float *normal)
{
BMLoop *l1 = edge->element->l;
@@ -1007,11 +1426,12 @@ static void stitch_calculate_edge_normal(BMEditMesh *em, UvEdge *edge, float *no
normalize_v2(normal);
}
-static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *UNUSED(arg))
+static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
{
int i, index = 0;
float pointsize = UI_GetThemeValuef(TH_VERTEX_SIZE);
- StitchPreviewer *stitch_preview = uv_get_stitch_previewer();
+ StitchState *state = (StitchState *)arg;
+ StitchPreviewer *stitch_preview = state->stitch_preview;
glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
glEnableClientState(GL_VERTEX_ARRAY);
@@ -1042,24 +1462,56 @@ static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *UN
glDisable(GL_BLEND);
/* draw vert preview */
- glPointSize(pointsize * 2.0f);
- UI_ThemeColor4(TH_STITCH_PREVIEW_STITCHABLE);
- glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_stitchable);
- glDrawArrays(GL_POINTS, 0, stitch_preview->num_stitchable);
-
- UI_ThemeColor4(TH_STITCH_PREVIEW_UNSTITCHABLE);
- glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_unstitchable);
- glDrawArrays(GL_POINTS, 0, stitch_preview->num_unstitchable);
+ if(state->mode == STITCH_VERT) {
+ glPointSize(pointsize * 2.0f);
+ UI_ThemeColor4(TH_STITCH_PREVIEW_STITCHABLE);
+ glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_stitchable);
+ glDrawArrays(GL_POINTS, 0, stitch_preview->num_stitchable);
+
+ UI_ThemeColor4(TH_STITCH_PREVIEW_UNSTITCHABLE);
+ glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_unstitchable);
+ glDrawArrays(GL_POINTS, 0, stitch_preview->num_unstitchable);
+ } else {
+ UI_ThemeColor4(TH_STITCH_PREVIEW_STITCHABLE);
+ glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_stitchable);
+ glDrawArrays(GL_LINES, 0, 2*stitch_preview->num_stitchable);
+
+ UI_ThemeColor4(TH_STITCH_PREVIEW_UNSTITCHABLE);
+ glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_unstitchable);
+ glDrawArrays(GL_LINES, 0, 2*stitch_preview->num_unstitchable);
+ }
glPopClientAttrib();
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glPointSize(1.0);
+}
+
+static UvEdge *uv_edge_get (BMLoop *l, StitchState *state)
+{
+ UvEdge tmp_edge;
+
+ UvElement *element1 = ED_uv_element_get(state->element_map, l->f, l);
+ UvElement *element2 = ED_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];
+
+ 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);
}
static int stitch_init(bContext *C, wmOperator *op)
{
/* for fast edge lookup... */
- GHash *edgeHash;
+ GHash *edge_hash;
/* ...and actual edge storage */
UvEdge *edges;
int total_edges;
@@ -1097,21 +1549,38 @@ static int stitch_init(bContext *C, wmOperator *op)
state->static_island = RNA_int_get(op->ptr, "static_island");
state->midpoints = RNA_boolean_get(op->ptr, "midpoint_snap");
state->clear_seams = RNA_boolean_get(op->ptr, "clear_seams");
- state->draw_handle = ED_region_draw_cb_activate(ar->type, stitch_draw, NULL, REGION_DRAW_POST_VIEW);
+ if (RNA_struct_property_is_set(op->ptr, "mode")) {
+ state->mode = RNA_enum_get(op->ptr, "mode");
+ } else {
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode & SCE_SELECT_VERTEX)
+ state->mode = STITCH_VERT;
+ else
+ state->mode = STITCH_EDGE;
+ } else {
+ if (ts->uv_selectmode & UV_SELECT_VERTEX) {
+ state->mode = STITCH_VERT;
+ } else {
+ state->mode = STITCH_EDGE;
+ }
+ }
+ }
+
+ state->draw_handle = ED_region_draw_cb_activate(ar->type, stitch_draw, state, REGION_DRAW_POST_VIEW);
/* in uv synch selection, all uv's are visible */
if (ts->uv_flag & UV_SYNC_SELECTION) {
- state->element_map = EDBM_uv_element_map_create(state->em, 0, 1);
+ state->element_map = EDBM_uv_element_map_create(state->em, FALSE, TRUE);
}
else {
- state->element_map = EDBM_uv_element_map_create(state->em, 1, 1);
+ state->element_map = EDBM_uv_element_map_create(state->em, TRUE, TRUE);
}
if (!state->element_map) {
- stitch_state_delete(state);
+ state_delete(state);
return 0;
}
/* Entirely possible if redoing last operator that static island is bigger than total number of islands.
- * This ensures we get no hang in the island checking code in stitch_process_data. */
+ * This ensures we get no hang in the island checking code in stitch_stitch_process_data. */
state->static_island %= state->element_map->totalIslands;
/* Count 'unique' uvs */
@@ -1121,22 +1590,21 @@ static int stitch_init(bContext *C, wmOperator *op)
}
}
+ /* 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;
- /* we can at most have totalUVs edges or uvs selected. Actually they are less, considering we store only
- * unique uvs for processing but I am accounting for all bizarre cases, especially for edges, this way */
- state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * counter, "uv_stitch_selection_stack");
state->map = map = MEM_mallocN(sizeof(*map) * state->element_map->totalUVs, "uv_stitch_unique_map");
/* Allocate the edge stack */
- edgeHash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "stitch_edge_hash");
+ 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, "stitch_all_edges");
- if (!state->selection_stack || !state->uvs || !map || !edgeHash || !all_edges) {
- stitch_state_delete(state);
+ if (!state->uvs || !map || !edge_hash || !all_edges) {
+ state_delete(state);
return 0;
}
@@ -1169,6 +1637,8 @@ static int stitch_init(bContext *C, wmOperator *op)
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
@@ -1182,12 +1652,12 @@ static int stitch_init(bContext *C, wmOperator *op)
all_edges[counter].uv2 = offset1;
}
- if (BLI_ghash_haskey(edgeHash, &all_edges[counter])) {
- char *flag = BLI_ghash_lookup(edgeHash, &all_edges[counter]);
- *flag = 0;
+ if (BLI_ghash_haskey(edge_hash, &all_edges[counter])) {
+ UvEdge *edge = BLI_ghash_lookup(edge_hash, &all_edges[counter]);
+ edge->flag = 0;
}
else {
- BLI_ghash_insert(edgeHash, &all_edges[counter], &(all_edges[counter].flag));
+ BLI_ghash_insert(edge_hash, &all_edges[counter], &all_edges[counter]);
all_edges[counter].flag = STITCH_BOUNDARY;
}
counter++;
@@ -1195,55 +1665,55 @@ static int stitch_init(bContext *C, wmOperator *op)
}
- ghi = BLI_ghashIterator_new(edgeHash);
- total_edges = 0;
- /* fill the edges with data */
- for (; !BLI_ghashIterator_isDone(ghi); BLI_ghashIterator_step(ghi)) {
- UvEdge *edge = ((UvEdge *)BLI_ghashIterator_getKey(ghi));
- if (edge->flag & STITCH_BOUNDARY) {
- total_edges++;
- }
- }
+ ghi = BLI_ghashIterator_new(edge_hash);
+ total_edges = BLI_ghash_size(edge_hash);
state->edges = edges = MEM_mallocN(sizeof(*edges) * total_edges, "stitch_edges");
- if (!ghi || !edges) {
- MEM_freeN(all_edges);
- stitch_state_delete(state);
+
+ /* I assume any system will be able to at least allocate an iterator :p */
+ if (!edges) {
+ BLI_ghashIterator_free(ghi);
+ state_delete(state);
return 0;
}
- state->total_boundary_edges = total_edges;
+ state->total_separate_edges = total_edges;
/* fill the edges with data */
- for (i = 0, BLI_ghashIterator_init(ghi, edgeHash); !BLI_ghashIterator_isDone(ghi); BLI_ghashIterator_step(ghi)) {
- UvEdge *edge = ((UvEdge *)BLI_ghashIterator_getKey(ghi));
- if (edge->flag & STITCH_BOUNDARY) {
- edges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(ghi));
- }
+ for (i = 0, BLI_ghashIterator_init(ghi, edge_hash); !BLI_ghashIterator_isDone(ghi); BLI_ghashIterator_step(ghi)) {
+ edges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(ghi));
}
/* cleanup temporary stuff */
BLI_ghashIterator_free(ghi);
MEM_freeN(all_edges);
- /* refill hash with new pointers to cleanup duplicates */
- BLI_ghash_free(edgeHash, NULL, NULL);
+ 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 opposite uv for a quad, or the next uv for a triangle. */
+ * the winding of the polygon (assuming counter-clockwise flow). */
for (i = 0; i < total_edges; i++) {
float normal[2];
- stitch_calculate_edge_normal(em, edges + i, normal);
+ if (edges[i].flag & STITCH_BOUNDARY) {
+ stitch_calculate_edge_normal(em, edges + i, normal);
- add_v2_v2(state->normals + edges[i].uv1 * 2, normal);
- add_v2_v2(state->normals + edges[i].uv2 * 2, normal);
+ add_v2_v2(state->normals + edges[i].uv1 * 2, normal);
+ add_v2_v2(state->normals + edges[i].uv2 * 2, normal);
- normalize_v2(state->normals + edges[i].uv1 * 2);
- normalize_v2(state->normals + edges[i].uv2 * 2);
+ normalize_v2(state->normals + edges[i].uv1 * 2);
+ normalize_v2(state->normals + edges[i].uv2 * 2);
+ }
}
@@ -1255,30 +1725,86 @@ static int stitch_init(bContext *C, wmOperator *op)
if (RNA_struct_property_is_set(op->ptr, "selection")) {
int faceIndex, elementIndex;
UvElement *element;
+ enum StitchModes stored_mode = RNA_enum_get(op->ptr, "stored_mode");
EDBM_index_arrays_ensure(em, BM_FACE);
- RNA_BEGIN (op->ptr, itemptr, "selection")
- {
- faceIndex = RNA_int_get(&itemptr, "face_index");
- elementIndex = RNA_int_get(&itemptr, "element_index");
- efa = EDBM_face_at_index(em, faceIndex);
- element = ED_uv_element_get(state->element_map, efa, BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex));
- stitch_select_uv(element, state, 1);
- }
- RNA_END;
+ if(stored_mode == STITCH_VERT) {
+ state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_uvs, "uv_stitch_selection_stack");
+ RNA_BEGIN (op->ptr, itemptr, "selection")
+ {
+ faceIndex = RNA_int_get(&itemptr, "face_index");
+ elementIndex = RNA_int_get(&itemptr, "element_index");
+ efa = EDBM_face_at_index(em, faceIndex);
+ element = ED_uv_element_get(state->element_map, efa, BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex));
+ stitch_select_uv(element, state, 1);
+ }
+ RNA_END;
+ } else {
+ state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_edges, "uv_stitch_selection_stack");
+
+ RNA_BEGIN (op->ptr, itemptr, "selection")
+ {
+ UvEdge tmp_edge, *edge;
+ int uv1, uv2;
+ faceIndex = RNA_int_get(&itemptr, "face_index");
+ elementIndex = RNA_int_get(&itemptr, "element_index");
+ efa = EDBM_face_at_index(em, faceIndex);
+ element = ED_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 = ED_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);
+ }
+ RNA_END;
+ }
+ /* if user has switched the operator mode after operation, we need to convert
+ * the stored format */
+ if (state->mode != stored_mode) {
+ state->mode = stored_mode;
+ stitch_switch_selection_mode(state);
+ }
/* Clear the selection */
RNA_collection_clear(op->ptr, "selection");
}
else {
- 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(em, scene, l)) {
- UvElement *element = ED_uv_element_get(state->element_map, efa, l);
- if (element) {
- stitch_select_uv(element, state, 1);
+ if(state->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(em, scene, l)) {
+ UvElement *element = ED_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) {
+ BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
+ if(uvedit_edge_select_test(em, scene, l)) {
+ UvEdge *edge = uv_edge_get(l, state);
+ if(edge) {
+ stitch_select_edge(edge, state, TRUE);
+ }
}
}
}
@@ -1301,8 +1827,9 @@ static int stitch_init(bContext *C, wmOperator *op)
}
}
- if (!stitch_process_data(state, scene, 0)) {
- stitch_state_delete(state);
+ if (!stitch_process_data(state, scene, FALSE)) {
+
+ state_delete(state);
return 0;
}
@@ -1323,7 +1850,7 @@ static int stitch_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
static void stitch_exit(bContext *C, wmOperator *op, int finished)
{
- StitchState *stitch_state;
+ StitchState *state;
Scene *scene;
SpaceImage *sima;
ScrArea *sa = CTX_wm_area(C);
@@ -1333,45 +1860,47 @@ static void stitch_exit(bContext *C, wmOperator *op, int finished)
obedit = CTX_data_edit_object(C);
sima = CTX_wm_space_image(C);
- stitch_state = (StitchState *)op->customdata;
+ state = (StitchState *)op->customdata;
if (finished) {
int i;
- RNA_float_set(op->ptr, "limit", stitch_state->limit_dist);
- RNA_boolean_set(op->ptr, "use_limit", stitch_state->use_limit);
- RNA_boolean_set(op->ptr, "snap_islands", stitch_state->snap_islands);
- RNA_int_set(op->ptr, "static_island", stitch_state->static_island);
- RNA_boolean_set(op->ptr, "midpoint_snap", stitch_state->midpoints);
+ RNA_float_set(op->ptr, "limit", state->limit_dist);
+ RNA_boolean_set(op->ptr, "use_limit", state->use_limit);
+ RNA_boolean_set(op->ptr, "snap_islands", state->snap_islands);
+ RNA_int_set(op->ptr, "static_island", state->static_island);
+ RNA_boolean_set(op->ptr, "midpoint_snap", state->midpoints);
+ RNA_enum_set(op->ptr, "mode", state->mode);
+ RNA_enum_set(op->ptr, "stored_mode", state->mode);
/* Store selection for re-execution of stitch */
- for (i = 0; i < stitch_state->selection_size; i++) {
+ for (i = 0; i < state->selection_size; i++) {
+ UvElement *element;
PointerRNA itemptr;
- UvElement *element = stitch_state->selection_stack[i];
-
+ if (state->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->face));
-
+ RNA_int_set(&itemptr, "face_index", BM_elem_index_get(element->l->f));
RNA_int_set(&itemptr, "element_index", element->tfindex);
}
-
uvedit_live_unwrap_update(sima, scene, obedit);
}
if (sa)
ED_area_headerprint(sa, NULL);
- ED_region_draw_cb_exit(CTX_wm_region(C)->type, stitch_state->draw_handle);
+ ED_region_draw_cb_exit(CTX_wm_region(C)->type, state->draw_handle);
DAG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- stitch_state_delete(stitch_state);
+ state_delete(state);
op->customdata = NULL;
-
- stitch_preview_delete();
}
@@ -1397,7 +1926,7 @@ static int stitch_exec(bContext *C, wmOperator *op)
}
}
-static void stitch_select(bContext *C, Scene *scene, wmEvent *event, StitchState *stitch_state)
+static void stitch_select(bContext *C, Scene *scene, wmEvent *event, StitchState *state)
{
/* add uv under mouse to processed uv's */
float co[2];
@@ -1406,42 +1935,52 @@ static void stitch_select(bContext *C, Scene *scene, wmEvent *event, StitchState
Image *ima = CTX_data_edit_image(C);
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
- uv_find_nearest_vert(scene, ima, stitch_state->em, co, NULL, &hit);
- if (hit.efa) {
- /* 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 */
+ if(state->mode == STITCH_VERT) {
+ uv_find_nearest_vert(scene, ima, state->em, co, NULL, &hit);
- /* This works due to setting of tmp in find nearest uv vert */
- UvElement *element = ED_uv_element_get(stitch_state->element_map, hit.efa, hit.l);
- stitch_select_uv(element, stitch_state, 0);
+ if (hit.efa) {
+ /* 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 */
+ /* This works due to setting of tmp in find nearest uv vert */
+ UvElement *element = ED_uv_element_get(state->element_map, hit.efa, hit.l);
+ stitch_select_uv(element, state, FALSE);
+
+ }
+ } else {
+ uv_find_nearest_edge(scene, ima, state->em, co, &hit);
+
+ if(hit.efa) {
+ UvEdge *edge = uv_edge_get(hit.l, state);
+ stitch_select_edge(edge, state, FALSE);
+ }
}
}
static int stitch_modal(bContext *C, wmOperator *op, wmEvent *event)
{
- StitchState *stitch_state;
+ StitchState *state;
Scene *scene = CTX_data_scene(C);
- stitch_state = (StitchState *)op->customdata;
+ state = (StitchState *)op->customdata;
switch (event->type) {
case MIDDLEMOUSE:
return OPERATOR_PASS_THROUGH;
- /* Cancel */
+ /* Cancel */
case ESCKEY:
return stitch_cancel(C, op);
case LEFTMOUSE:
if (event->shift && (U.flag & USER_LMOUSESELECT)) {
- if (event->val == KM_RELEASE) {
- stitch_select(C, scene, event, stitch_state);
+ if (event->val == KM_PRESS) {
+ stitch_select(C, scene, event, state);
- if (!stitch_process_data(stitch_state, scene, 0)) {
+ if (!stitch_process_data(state, scene, FALSE)) {
return stitch_cancel(C, op);
}
}
@@ -1450,7 +1989,7 @@ static int stitch_modal(bContext *C, wmOperator *op, wmEvent *event)
case PADENTER:
case RETKEY:
if (event->val == KM_PRESS) {
- if (stitch_process_data(stitch_state, scene, 1)) {
+ if (stitch_process_data(state, scene, TRUE)) {
stitch_exit(C, op, 1);
return OPERATOR_FINISHED;
}
@@ -1461,12 +2000,12 @@ static int stitch_modal(bContext *C, wmOperator *op, wmEvent *event)
else {
return OPERATOR_PASS_THROUGH;
}
- /* Increase limit */
+ /* Increase limit */
case PADPLUSKEY:
case WHEELUPMOUSE:
if (event->val == KM_PRESS && event->alt) {
- stitch_state->limit_dist += 0.01f;
- if (!stitch_process_data(stitch_state, scene, 0)) {
+ state->limit_dist += 0.01f;
+ if (!stitch_process_data(state, scene, FALSE)) {
return stitch_cancel(C, op);
}
break;
@@ -1474,13 +2013,13 @@ static int stitch_modal(bContext *C, wmOperator *op, wmEvent *event)
else {
return OPERATOR_PASS_THROUGH;
}
- /* Decrease limit */
+ /* Decrease limit */
case PADMINUS:
case WHEELDOWNMOUSE:
if (event->val == KM_PRESS && event->alt) {
- stitch_state->limit_dist -= 0.01f;
- stitch_state->limit_dist = MAX2(0.01f, stitch_state->limit_dist);
- if (!stitch_process_data(stitch_state, scene, 0)) {
+ state->limit_dist -= 0.01f;
+ state->limit_dist = MAX2(0.01f, state->limit_dist);
+ if (!stitch_process_data(state, scene, FALSE)) {
return stitch_cancel(C, op);
}
break;
@@ -1489,11 +2028,11 @@ static int stitch_modal(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_PASS_THROUGH;
}
- /* Use Limit (Default off)*/
+ /* Use Limit (Default off)*/
case LKEY:
if (event->val == KM_PRESS) {
- stitch_state->use_limit = !stitch_state->use_limit;
- if (!stitch_process_data(stitch_state, scene, 0)) {
+ state->use_limit = !state->use_limit;
+ if (!stitch_process_data(state, scene, FALSE)) {
return stitch_cancel(C, op);
}
break;
@@ -1502,10 +2041,10 @@ static int stitch_modal(bContext *C, wmOperator *op, wmEvent *event)
case IKEY:
if (event->val == KM_PRESS) {
- stitch_state->static_island++;
- stitch_state->static_island %= stitch_state->element_map->totalIslands;
+ state->static_island++;
+ state->static_island %= state->element_map->totalIslands;
- if (!stitch_process_data(stitch_state, scene, 0)) {
+ if (!stitch_process_data(state, scene, FALSE)) {
return stitch_cancel(C, op);
}
break;
@@ -1514,33 +2053,33 @@ static int stitch_modal(bContext *C, wmOperator *op, wmEvent *event)
case MKEY:
if (event->val == KM_PRESS) {
- stitch_state->midpoints = !stitch_state->midpoints;
- if (!stitch_process_data(stitch_state, scene, 0)) {
+ state->midpoints = !state->midpoints;
+ if (!stitch_process_data(state, scene, FALSE)) {
return stitch_cancel(C, op);
}
}
break;
- /* Select geometry*/
+ /* Select geometry*/
case RIGHTMOUSE:
if (!event->shift) {
return stitch_cancel(C, op);
}
- if (event->val == KM_RELEASE && !(U.flag & USER_LMOUSESELECT)) {
- stitch_select(C, scene, event, stitch_state);
+ if (event->val == KM_PRESS && !(U.flag & USER_LMOUSESELECT)) {
+ stitch_select(C, scene, event, state);
- if (!stitch_process_data(stitch_state, scene, 0)) {
+ if (!stitch_process_data(state, scene, FALSE)) {
return stitch_cancel(C, op);
}
break;
}
return OPERATOR_RUNNING_MODAL;
- /* snap islands on/off */
+ /* snap islands on/off */
case SKEY:
if (event->val == KM_PRESS) {
- stitch_state->snap_islands = !stitch_state->snap_islands;
- if (!stitch_process_data(stitch_state, scene, 0)) {
+ state->snap_islands = !state->snap_islands;
+ if (!stitch_process_data(state, scene, FALSE)) {
return stitch_cancel(C, op);
}
break;
@@ -1549,12 +2088,23 @@ static int stitch_modal(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
+ /* switch between edge/vertex mode */
+ case TABKEY:
+ if (event->val == KM_PRESS) {
+ stitch_switch_selection_mode(state);
+
+ if (!stitch_process_data(state, scene, FALSE)) {
+ return stitch_cancel(C, op);
+ }
+ }
+ break;
+
default:
return OPERATOR_RUNNING_MODAL;
}
/* if updated settings, renew feedback message */
- stitch_update_header(stitch_state, C);
+ stitch_update_header(state, C);
ED_region_tag_redraw(CTX_wm_region(C));
return OPERATOR_RUNNING_MODAL;
}
@@ -1563,6 +2113,12 @@ void UV_OT_stitch(wmOperatorType *ot)
{
PropertyRNA *prop;
+ static 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";
@@ -1589,6 +2145,11 @@ void UV_OT_stitch(wmOperatorType *ot)
"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);