Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / uvedit / uvedit_smart_stitch.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Antony Riakiotakis.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/uvedit/uvedit_smart_stitch.c
29  *  \ingroup eduv
30  */
31
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include <math.h>
36
37 #include "MEM_guardedalloc.h"
38
39 #include "DNA_object_types.h"
40 #include "DNA_meshdata_types.h"
41 #include "DNA_scene_types.h"
42
43 #include "BLI_utildefines.h"
44 #include "BLI_ghash.h"
45 #include "BLI_math.h"
46 #include "BLI_math_vector.h"
47 #include "BLI_string.h"
48
49 #include "BLT_translation.h"
50
51 #include "BIF_gl.h"
52
53 #include "BKE_context.h"
54 #include "BKE_customdata.h"
55 #include "BKE_mesh_mapping.h"
56 #include "BKE_editmesh.h"
57
58 #include "DEG_depsgraph.h"
59
60 #include "UI_interface.h"
61
62 #include "ED_mesh.h"
63 #include "ED_uvedit.h"
64 #include "ED_screen.h"
65 #include "ED_space_api.h"
66
67 #include "GPU_batch.h"
68
69 #include "RNA_access.h"
70 #include "RNA_define.h"
71
72 #include "WM_api.h"
73 #include "WM_types.h"
74
75 #include "UI_view2d.h"
76 #include "UI_resources.h"
77
78 #include "uvedit_intern.h"
79
80 /* ********************** smart stitch operator *********************** */
81
82 /* object that stores display data for previewing before confirming stitching */
83 typedef struct StitchPreviewer {
84         /* here we'll store the preview triangle indices of the mesh */
85         float *preview_polys;
86         /* uvs per polygon. */
87         unsigned int *uvs_per_polygon;
88         /*number of preview polygons */
89         unsigned int num_polys;
90         /* preview data. These will be either the previewed vertices or edges depending on stitch mode settings */
91         float *preview_stitchable;
92         float *preview_unstitchable;
93         /* here we'll store the number of elements to be drawn */
94         unsigned int num_stitchable;
95         unsigned int num_unstitchable;
96         unsigned int preview_uvs;
97         /* ...and here we'll store the static island triangles */
98         float *static_tris;
99         unsigned int num_static_tris;
100 } StitchPreviewer;
101
102
103 struct IslandStitchData;
104
105 /**
106  * This is a straightforward implementation, count the UVs in the island
107  * that will move and take the mean displacement/rotation and apply it to all
108  * elements of the island except from the stitchable.
109  */
110 typedef struct IslandStitchData {
111         /* rotation can be used only for edges, for vertices there is no such notion */
112         float rotation;
113         float rotation_neg;
114         float translation[2];
115         /* Used for rotation, the island will rotate around this point */
116         float medianPoint[2];
117         int numOfElements;
118         int num_rot_elements;
119         int num_rot_elements_neg;
120         /* flag to remember if island has been added for preview */
121         char addedForPreview;
122         /* flag an island to be considered for determining static island */
123         char stitchableCandidate;
124         /* if edge rotation is used, flag so that vertex rotation is not used */
125         bool use_edge_rotation;
126 } IslandStitchData;
127
128 /* just for averaging UVs */
129 typedef struct UVVertAverage {
130         float uv[2];
131         unsigned short count;
132 } UVVertAverage;
133
134 typedef struct UvEdge {
135         /* index to uv buffer */
136         unsigned int uv1;
137         unsigned int uv2;
138         /* general use flag (Used to check if edge is boundary here, and propagates to adjacency elements) */
139         unsigned char flag;
140         /* element that guarantees element->face has the edge on element->tfindex and element->tfindex+1 is the second uv */
141         UvElement *element;
142         /* next uv edge with the same exact vertices as this one.. Calculated at startup to save time */
143         struct UvEdge *next;
144         /* point to first of common edges. Needed for iteration */
145         struct UvEdge *first;
146 } UvEdge;
147
148
149 /* stitch state object */
150 typedef struct StitchState {
151         float aspect;
152         /* use limit flag */
153         bool use_limit;
154         /* limit to operator, same as original operator */
155         float limit_dist;
156         /* snap uv islands together during stitching */
157         bool snap_islands;
158         /* stitch at midpoints or at islands */
159         bool midpoints;
160         /* object for editmesh */
161         Object *obedit;
162         /* editmesh, cached for use in modal handler */
163         BMEditMesh *em;
164         /* clear seams of stitched edges after stitch */
165         bool clear_seams;
166         /* element map for getting info about uv connectivity */
167         UvElementMap *element_map;
168         /* edge container */
169         UvEdge *uvedges;
170         /* container of first of a group of coincident uvs, these will be operated upon */
171         UvElement **uvs;
172         /* maps uvelements to their first coincident uv */
173         int *map;
174         /* 2D normals per uv to calculate rotation for snapping */
175         float *normals;
176         /* edge storage */
177         UvEdge *edges;
178         /* hash for quick lookup of edges */
179         GHash *edge_hash;
180
181         /* count of separate uvs and edges */
182         int total_separate_edges;
183         int total_separate_uvs;
184         /* hold selection related information */
185         void **selection_stack;
186         int selection_size;
187         /* island that stays in place */
188         int static_island;
189         /* store number of primitives per face so that we can allocate the active island buffer later */
190         unsigned int *tris_per_island;
191
192         /* vert or edge mode used for stitching */
193         char mode;
194         /* handle for drawing */
195         void *draw_handle;
196         /* preview data */
197         StitchPreviewer *stitch_preview;
198 } StitchState;
199
200 typedef struct PreviewPosition {
201         int data_position;
202         int polycount_position;
203 } PreviewPosition;
204 /*
205  * defines for UvElement/UcEdge flags
206  */
207 #define STITCH_SELECTED 1
208 #define STITCH_STITCHABLE 2
209 #define STITCH_PROCESSED 4
210 #define STITCH_BOUNDARY 8
211 #define STITCH_STITCHABLE_CANDIDATE 16
212
213 #define STITCH_NO_PREVIEW -1
214
215 enum StitchModes {
216         STITCH_VERT,
217         STITCH_EDGE
218 };
219
220 /* constructor */
221 static StitchPreviewer *stitch_preview_init(void)
222 {
223         StitchPreviewer *stitch_preview;
224
225         stitch_preview = MEM_mallocN(sizeof(StitchPreviewer), "stitch_previewer");
226         stitch_preview->preview_polys = NULL;
227         stitch_preview->preview_stitchable = NULL;
228         stitch_preview->preview_unstitchable = NULL;
229         stitch_preview->uvs_per_polygon = NULL;
230
231         stitch_preview->preview_uvs = 0;
232         stitch_preview->num_polys = 0;
233         stitch_preview->num_stitchable = 0;
234         stitch_preview->num_unstitchable = 0;
235
236         stitch_preview->static_tris = NULL;
237
238         stitch_preview->num_static_tris = 0;
239
240         return stitch_preview;
241 }
242
243 /* destructor...yeah this should be C++ :) */
244 static void stitch_preview_delete(StitchPreviewer *stitch_preview)
245 {
246         if (stitch_preview) {
247                 if (stitch_preview->preview_polys) {
248                         MEM_freeN(stitch_preview->preview_polys);
249                         stitch_preview->preview_polys = NULL;
250                 }
251                 if (stitch_preview->uvs_per_polygon) {
252                         MEM_freeN(stitch_preview->uvs_per_polygon);
253                         stitch_preview->uvs_per_polygon = NULL;
254                 }
255                 if (stitch_preview->preview_stitchable) {
256                         MEM_freeN(stitch_preview->preview_stitchable);
257                         stitch_preview->preview_stitchable = NULL;
258                 }
259                 if (stitch_preview->preview_unstitchable) {
260                         MEM_freeN(stitch_preview->preview_unstitchable);
261                         stitch_preview->preview_unstitchable = NULL;
262                 }
263                 if (stitch_preview->static_tris) {
264                         MEM_freeN(stitch_preview->static_tris);
265                         stitch_preview->static_tris = NULL;
266                 }
267                 MEM_freeN(stitch_preview);
268         }
269 }
270
271 /* This function updates the header of the UV editor when the stitch tool updates its settings */
272 static void stitch_update_header(StitchState *state, bContext *C)
273 {
274         const char *str = IFACE_(
275             "Mode(TAB) %s, "
276             "(S)nap %s, "
277             "(M)idpoints %s, "
278             "(L)imit %.2f (Alt Wheel adjust) %s, "
279             "Switch (I)sland, "
280             "shift select vertices"
281         );
282
283         char msg[UI_MAX_DRAW_STR];
284         ScrArea *sa = CTX_wm_area(C);
285
286         if (sa) {
287                 BLI_snprintf(msg, sizeof(msg), str,
288                              state->mode == STITCH_VERT ? IFACE_("Vertex") : IFACE_("Edge"),
289                              WM_bool_as_string(state->snap_islands),
290                              WM_bool_as_string(state->midpoints),
291                              state->limit_dist,
292                              WM_bool_as_string(state->use_limit));
293
294                 ED_area_headerprint(sa, msg);
295         }
296 }
297
298 static int getNumOfIslandUvs(UvElementMap *elementMap, int island)
299 {
300         if (island == elementMap->totalIslands - 1) {
301                 return elementMap->totalUVs - elementMap->islandIndices[island];
302         }
303         else {
304                 return elementMap->islandIndices[island + 1] - elementMap->islandIndices[island];
305         }
306 }
307
308 static void stitch_uv_rotate(float mat[2][2], float medianPoint[2], float uv[2], float aspect)
309 {
310         float uv_rotation_result[2];
311
312         uv[1] /= aspect;
313
314         sub_v2_v2(uv, medianPoint);
315         mul_v2_m2v2(uv_rotation_result, mat, uv);
316         add_v2_v2v2(uv, uv_rotation_result, medianPoint);
317
318         uv[1] *= aspect;
319 }
320
321 /* check if two uvelements are stitchable. This should only operate on -different- separate UvElements */
322 static bool stitch_check_uvs_stitchable(UvElement *element, UvElement *element_iter, StitchState *state)
323 {
324         BMesh *bm = state->em->bm;
325         float limit;
326
327         if (element_iter == element) {
328                 return 0;
329         }
330
331         limit = state->limit_dist;
332
333         if (state->use_limit) {
334                 MLoopUV *luv, *luv_iter;
335                 BMLoop *l;
336
337
338                 l = element->l;
339                 luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
340                 l = element_iter->l;
341                 luv_iter = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
342
343                 if (fabsf(luv->uv[0] - luv_iter->uv[0]) < limit &&
344                     fabsf(luv->uv[1] - luv_iter->uv[1]) < limit)
345                 {
346                         return 1;
347                 }
348                 else {
349                         return 0;
350                 }
351         }
352         else {
353                 return 1;
354         }
355 }
356
357 static bool stitch_check_edges_stitchable(UvEdge *edge, UvEdge *edge_iter, StitchState *state)
358 {
359         BMesh *bm = state->em->bm;
360         float limit;
361
362         if (edge_iter == edge) {
363                 return 0;
364         }
365
366         limit = state->limit_dist;
367
368         if (state->use_limit) {
369                 BMLoop *l;
370                 MLoopUV *luv_orig1, *luv_iter1;
371                 MLoopUV *luv_orig2, *luv_iter2;
372
373                 l = state->uvs[edge->uv1]->l;
374                 luv_orig1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
375                 l = state->uvs[edge_iter->uv1]->l;
376                 luv_iter1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
377
378                 l = state->uvs[edge->uv2]->l;
379                 luv_orig2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
380                 l = state->uvs[edge_iter->uv2]->l;
381                 luv_iter2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
382
383                 if (fabsf(luv_orig1->uv[0] - luv_iter1->uv[0]) < limit &&
384                     fabsf(luv_orig1->uv[1] - luv_iter1->uv[1]) < limit &&
385                     fabsf(luv_orig2->uv[0] - luv_iter2->uv[0]) < limit &&
386                     fabsf(luv_orig2->uv[1] - luv_iter2->uv[1]) < limit)
387                 {
388                         return 1;
389                 }
390                 else {
391                         return 0;
392                 }
393         }
394         else {
395                 return 1;
396         }
397 }
398
399 static bool stitch_check_uvs_state_stitchable(UvElement *element, UvElement *element_iter, StitchState *state)
400 {
401         if ((state->snap_islands && element->island == element_iter->island) ||
402             (!state->midpoints && element->island == element_iter->island))
403         {
404                 return 0;
405         }
406
407         return stitch_check_uvs_stitchable(element, element_iter, state);
408 }
409
410
411 static bool stitch_check_edges_state_stitchable(UvEdge *edge, UvEdge *edge_iter, StitchState *state)
412 {
413         if ((state->snap_islands && edge->element->island == edge_iter->element->island) ||
414             (!state->midpoints && edge->element->island == edge_iter->element->island))
415         {
416                 return 0;
417         }
418
419         return stitch_check_edges_stitchable(edge, edge_iter, state);
420 }
421
422 /* calculate snapping for islands */
423 static void stitch_calculate_island_snapping(
424         StitchState *state, PreviewPosition *preview_position, StitchPreviewer *preview,
425         IslandStitchData *island_stitch_data, int final)
426 {
427         BMesh *bm = state->em->bm;
428         int i;
429         UvElement *element;
430
431         for (i = 0; i < state->element_map->totalIslands; i++) {
432                 if (island_stitch_data[i].addedForPreview) {
433                         int numOfIslandUVs = 0, j;
434                         int totelem = island_stitch_data[i].num_rot_elements_neg + island_stitch_data[i].num_rot_elements;
435                         float rotation;
436                         float rotation_mat[2][2];
437
438                         /* check to avoid divide by 0 */
439                         if (island_stitch_data[i].num_rot_elements > 1)
440                                 island_stitch_data[i].rotation /= island_stitch_data[i].num_rot_elements;
441
442                         if (island_stitch_data[i].num_rot_elements_neg > 1)
443                                 island_stitch_data[i].rotation_neg /= island_stitch_data[i].num_rot_elements_neg;
444
445                         if (island_stitch_data[i].numOfElements > 1) {
446                                 island_stitch_data[i].medianPoint[0] /= island_stitch_data[i].numOfElements;
447                                 island_stitch_data[i].medianPoint[1] /= island_stitch_data[i].numOfElements;
448
449                                 island_stitch_data[i].translation[0] /= island_stitch_data[i].numOfElements;
450                                 island_stitch_data[i].translation[1] /= island_stitch_data[i].numOfElements;
451                         }
452
453                         island_stitch_data[i].medianPoint[1] /= state->aspect;
454                         if ((island_stitch_data[i].rotation + island_stitch_data[i].rotation_neg < (float)M_PI_2) ||
455                             island_stitch_data[i].num_rot_elements == 0 || island_stitch_data[i].num_rot_elements_neg == 0)
456                         {
457                                 rotation = (island_stitch_data[i].rotation * island_stitch_data[i].num_rot_elements -
458                                             island_stitch_data[i].rotation_neg *
459                                             island_stitch_data[i].num_rot_elements_neg) / totelem;
460                         }
461                         else {
462                                 rotation = (island_stitch_data[i].rotation * island_stitch_data[i].num_rot_elements +
463                                             (2.0f * (float)M_PI - island_stitch_data[i].rotation_neg) *
464                                             island_stitch_data[i].num_rot_elements_neg) / totelem;
465                         }
466
467                         angle_to_mat2(rotation_mat, rotation);
468                         numOfIslandUVs = getNumOfIslandUvs(state->element_map, i);
469                         element = &state->element_map->buf[state->element_map->islandIndices[i]];
470                         for (j = 0; j < numOfIslandUVs; j++, element++) {
471                                 /* stitchable uvs have already been processed, don't process */
472                                 if (!(element->flag & STITCH_PROCESSED)) {
473                                         MLoopUV *luv;
474                                         BMLoop *l;
475
476                                         l = element->l;
477                                         luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
478
479                                         if (final) {
480
481                                                 stitch_uv_rotate(rotation_mat, island_stitch_data[i].medianPoint, luv->uv, state->aspect);
482
483                                                 add_v2_v2(luv->uv, island_stitch_data[i].translation);
484                                         }
485
486                                         else {
487
488                                                 int face_preview_pos = preview_position[BM_elem_index_get(element->l->f)].data_position;
489
490                                                 stitch_uv_rotate(rotation_mat, island_stitch_data[i].medianPoint,
491                                                                  preview->preview_polys + face_preview_pos + 2 * element->tfindex, state->aspect);
492
493                                                 add_v2_v2(preview->preview_polys + face_preview_pos + 2 * element->tfindex,
494                                                           island_stitch_data[i].translation);
495                                         }
496                                 }
497                                 /* cleanup */
498                                 element->flag &= STITCH_SELECTED;
499                         }
500                 }
501         }
502 }
503
504
505
506 static void stitch_island_calculate_edge_rotation(
507         UvEdge *edge, StitchState *state, UVVertAverage *uv_average, unsigned int *uvfinal_map,
508         IslandStitchData *island_stitch_data)
509 {
510         BMesh *bm = state->em->bm;
511         UvElement *element1, *element2;
512         float uv1[2], uv2[2];
513         float edgecos, edgesin;
514         int index1, index2;
515         float rotation;
516         MLoopUV *luv1, *luv2;
517
518         element1 = state->uvs[edge->uv1];
519         element2 = state->uvs[edge->uv2];
520
521         luv1 = CustomData_bmesh_get(&bm->ldata, element1->l->head.data, CD_MLOOPUV);
522         luv2 = CustomData_bmesh_get(&bm->ldata, element2->l->head.data, CD_MLOOPUV);
523
524         if (state->mode == STITCH_VERT) {
525                 index1 = uvfinal_map[element1 - state->element_map->buf];
526                 index2 = uvfinal_map[element2 - state->element_map->buf];
527         }
528         else {
529                 index1 = edge->uv1;
530                 index2 = edge->uv2;
531         }
532         /* the idea here is to take the directions of the edges and find the rotation between final and initial
533          * direction. This, using inner and outer vector products, gives the angle. Directions are differences so... */
534         uv1[0] = luv2->uv[0] - luv1->uv[0];
535         uv1[1] = luv2->uv[1] - luv1->uv[1];
536
537         uv1[1] /= state->aspect;
538
539         uv2[0] = uv_average[index2].uv[0] - uv_average[index1].uv[0];
540         uv2[1] = uv_average[index2].uv[1] - uv_average[index1].uv[1];
541
542         uv2[1] /= state->aspect;
543
544         normalize_v2(uv1);
545         normalize_v2(uv2);
546
547         edgecos = dot_v2v2(uv1, uv2);
548         edgesin = cross_v2v2(uv1, uv2);
549         rotation = acosf(max_ff(-1.0f, min_ff(1.0f, edgecos)));
550
551         if (edgesin > 0.0f) {
552                 island_stitch_data[element1->island].num_rot_elements++;
553                 island_stitch_data[element1->island].rotation += rotation;
554         }
555         else {
556                 island_stitch_data[element1->island].num_rot_elements_neg++;
557                 island_stitch_data[element1->island].rotation_neg += rotation;
558         }
559 }
560
561
562 static void stitch_island_calculate_vert_rotation(
563         UvElement *element, StitchState *state,
564         IslandStitchData *island_stitch_data)
565 {
566         float edgecos = 1.0f, edgesin = 0.0f;
567         int index;
568         UvElement *element_iter;
569         float rotation = 0, rotation_neg = 0;
570         int rot_elem = 0, rot_elem_neg = 0;
571         BMLoop *l;
572
573         if (element->island == state->static_island && !state->midpoints)
574                 return;
575
576         l = element->l;
577
578         index = BM_elem_index_get(l->v);
579
580         element_iter = state->element_map->vert[index];
581
582         for (; element_iter; element_iter = element_iter->next) {
583                 if (element_iter->separate && stitch_check_uvs_state_stitchable(element, element_iter, state)) {
584                         int index_tmp1, index_tmp2;
585                         float normal[2];
586
587                         /* only calculate rotation against static island uv verts */
588                         if (!state->midpoints && element_iter->island != state->static_island)
589                                 continue;
590
591                         index_tmp1 = element_iter - state->element_map->buf;
592                         index_tmp1 = state->map[index_tmp1];
593                         index_tmp2 = element - state->element_map->buf;
594                         index_tmp2 = state->map[index_tmp2];
595
596                         negate_v2_v2(normal, state->normals + index_tmp2 * 2);
597                         edgecos = dot_v2v2(normal, state->normals + index_tmp1 * 2);
598                         edgesin = cross_v2v2(normal, state->normals + index_tmp1 * 2);
599                         if (edgesin > 0.0f) {
600                                 rotation += acosf(max_ff(-1.0f, min_ff(1.0f, edgecos)));
601                                 rot_elem++;
602                         }
603                         else {
604                                 rotation_neg += acosf(max_ff(-1.0f, min_ff(1.0f, edgecos)));
605                                 rot_elem_neg++;
606                         }
607                 }
608         }
609
610         if (state->midpoints) {
611                 rotation /= 2.0f;
612                 rotation_neg /= 2.0f;
613         }
614         island_stitch_data[element->island].num_rot_elements += rot_elem;
615         island_stitch_data[element->island].rotation += rotation;
616         island_stitch_data[element->island].num_rot_elements_neg += rot_elem_neg;
617         island_stitch_data[element->island].rotation_neg += rotation_neg;
618 }
619
620
621 static void state_delete(StitchState *state)
622 {
623         if (state) {
624                 if (state->element_map) {
625                         BM_uv_element_map_free(state->element_map);
626                 }
627                 if (state->uvs) {
628                         MEM_freeN(state->uvs);
629                 }
630                 if (state->selection_stack) {
631                         MEM_freeN(state->selection_stack);
632                 }
633                 if (state->tris_per_island) {
634                         MEM_freeN(state->tris_per_island);
635                 }
636                 if (state->map) {
637                         MEM_freeN(state->map);
638                 }
639                 if (state->normals) {
640                         MEM_freeN(state->normals);
641                 }
642                 if (state->edges) {
643                         MEM_freeN(state->edges);
644                 }
645                 if (state->stitch_preview) {
646                         stitch_preview_delete(state->stitch_preview);
647                 }
648                 if (state->edge_hash) {
649                         BLI_ghash_free(state->edge_hash, NULL, NULL);
650                 }
651                 MEM_freeN(state);
652         }
653 }
654
655 static void stitch_uv_edge_generate_linked_edges(GHash *edge_hash, StitchState *state)
656 {
657         UvEdge *edges = state->edges;
658         const int *map = state->map;
659         UvElementMap *element_map = state->element_map;
660         UvElement *first_element = element_map->buf;
661         int i;
662
663         for (i = 0; i < state->total_separate_edges; i++) {
664                 UvEdge *edge = edges + i;
665
666                 if (edge->first)
667                         continue;
668
669                 /* only boundary edges can be stitched. Yes. Sorry about that :p */
670                 if (edge->flag & STITCH_BOUNDARY) {
671                         UvElement *element1 = state->uvs[edge->uv1];
672                         UvElement *element2 = state->uvs[edge->uv2];
673
674                         /* Now iterate through all faces and try to find edges sharing the same vertices */
675                         UvElement *iter1 = element_map->vert[BM_elem_index_get(element1->l->v)];
676                         UvEdge *last_set = edge;
677                         int elemindex2 = BM_elem_index_get(element2->l->v);
678
679                         edge->first = edge;
680
681                         for (; iter1; iter1 = iter1->next) {
682                                 UvElement *iter2 = NULL;
683
684                                 /* check to see if other vertex of edge belongs to same vertex as */
685                                 if (BM_elem_index_get(iter1->l->next->v) == elemindex2)
686                                         iter2 = BM_uv_element_get(element_map, iter1->l->f, iter1->l->next);
687                                 else if (BM_elem_index_get(iter1->l->prev->v) == elemindex2)
688                                         iter2 = BM_uv_element_get(element_map, iter1->l->f, iter1->l->prev);
689
690                                 if (iter2) {
691                                         int index1 = map[iter1 - first_element];
692                                         int index2 = map[iter2 - first_element];
693                                         UvEdge edgetmp;
694                                         UvEdge *edge2, *eiter;
695                                         bool valid = true;
696
697                                         /* make sure the indices are well behaved */
698                                         if (index1 > index2) {
699                                                 SWAP(int, index1, index2);
700                                         }
701
702                                         edgetmp.uv1 = index1;
703                                         edgetmp.uv2 = index2;
704
705                                         /* get the edge from the hash */
706                                         edge2 = BLI_ghash_lookup(edge_hash, &edgetmp);
707
708                                         /* more iteration to make sure non-manifold case is handled nicely */
709                                         for (eiter = edge; eiter; eiter = eiter->next) {
710                                                 if (edge2 == eiter) {
711                                                         valid = false;
712                                                         break;
713                                                 }
714                                         }
715
716                                         if (valid) {
717                                                 /* here I am taking care of non manifold case, assuming more than two matching edges.
718                                                  * I am not too sure we want this though */
719                                                 last_set->next = edge2;
720                                                 last_set = edge2;
721                                                 /* set first, similarly to uv elements. Now we can iterate among common edges easily */
722                                                 edge2->first = edge;
723                                         }
724                                 }
725                         }
726                 }
727                 else {
728                         /* so stitchability code works */
729                         edge->first = edge;
730                 }
731         }
732 }
733
734
735 /* checks for remote uvs that may be stitched with a certain uv, flags them if stitchable. */
736 static void determine_uv_stitchability(
737         UvElement *element, StitchState *state,
738         IslandStitchData *island_stitch_data)
739 {
740         int vert_index;
741         UvElement *element_iter;
742         BMLoop *l;
743
744         l = element->l;
745
746         vert_index = BM_elem_index_get(l->v);
747         element_iter = state->element_map->vert[vert_index];
748
749         for (; element_iter; element_iter = element_iter->next) {
750                 if (element_iter->separate) {
751                         if (stitch_check_uvs_stitchable(element, element_iter, state)) {
752                                 island_stitch_data[element_iter->island].stitchableCandidate = 1;
753                                 island_stitch_data[element->island].stitchableCandidate = 1;
754                                 element->flag |= STITCH_STITCHABLE_CANDIDATE;
755                         }
756                 }
757         }
758 }
759
760 static void determine_uv_edge_stitchability(
761         UvEdge *edge, StitchState *state,
762         IslandStitchData *island_stitch_data)
763 {
764         UvEdge *edge_iter = edge->first;
765
766         for (; edge_iter; edge_iter = edge_iter->next) {
767                 if (stitch_check_edges_stitchable(edge, edge_iter, state)) {
768                         island_stitch_data[edge_iter->element->island].stitchableCandidate = 1;
769                         island_stitch_data[edge->element->island].stitchableCandidate = 1;
770                         edge->flag |= STITCH_STITCHABLE_CANDIDATE;
771                 }
772         }
773 }
774
775
776 /* set preview buffer position of UV face in editface->tmp.l */
777 static void stitch_set_face_preview_buffer_position(
778         BMFace *efa, StitchPreviewer *preview, PreviewPosition *preview_position)
779 {
780         int index = BM_elem_index_get(efa);
781
782         if (preview_position[index].data_position == STITCH_NO_PREVIEW) {
783                 preview_position[index].data_position = preview->preview_uvs * 2;
784                 preview_position[index].polycount_position = preview->num_polys++;
785                 preview->preview_uvs += efa->len;
786         }
787 }
788
789
790 /* setup face preview for all coincident uvs and their faces */
791 static void stitch_setup_face_preview_for_uv_group(
792         UvElement *element, StitchState *state, IslandStitchData *island_stitch_data,
793         PreviewPosition *preview_position)
794 {
795         StitchPreviewer *preview = state->stitch_preview;
796
797         /* static island does not change so returning immediately */
798         if (state->snap_islands && !state->midpoints && state->static_island == element->island)
799                 return;
800
801         if (state->snap_islands) {
802                 island_stitch_data[element->island].addedForPreview = 1;
803         }
804
805         do {
806                 stitch_set_face_preview_buffer_position(element->l->f, preview, preview_position);
807                 element = element->next;
808         } while (element && !element->separate);
809 }
810
811
812 /* checks if uvs are indeed stitchable and registers so that they can be shown in preview */
813 static void stitch_validate_uv_stitchability(
814         UvElement *element, StitchState *state, IslandStitchData *island_stitch_data,
815         PreviewPosition *preview_position)
816 {
817         UvElement *element_iter;
818         StitchPreviewer *preview = state->stitch_preview;
819         int vert_index;
820         BMLoop *l;
821
822         l = element->l;
823
824         vert_index = BM_elem_index_get(l->v);
825
826         element_iter = state->element_map->vert[vert_index];
827
828         for (; element_iter; element_iter = element_iter->next) {
829                 if (element_iter->separate) {
830                         if (element_iter == element)
831                                 continue;
832                         if (stitch_check_uvs_state_stitchable(element, element_iter, state)) {
833                                 if ((element_iter->island == state->static_island) || (element->island == state->static_island)) {
834                                         element->flag |= STITCH_STITCHABLE;
835                                         preview->num_stitchable++;
836                                         stitch_setup_face_preview_for_uv_group(element, state, island_stitch_data, preview_position);
837                                         return;
838                                 }
839                         }
840                 }
841         }
842
843         /* this can happen if the uvs to be stitched are not on a stitchable island */
844         if (!(element->flag & STITCH_STITCHABLE)) {
845                 preview->num_unstitchable++;
846         }
847 }
848
849
850 static void stitch_validate_edge_stitchability(
851         UvEdge *edge, StitchState *state, IslandStitchData *island_stitch_data,
852         PreviewPosition *preview_position)
853 {
854         UvEdge *edge_iter = edge->first;
855         StitchPreviewer *preview = state->stitch_preview;
856
857         for (; edge_iter; edge_iter = edge_iter->next) {
858                 if (edge_iter == edge)
859                         continue;
860                 if (stitch_check_edges_state_stitchable(edge, edge_iter, state)) {
861                         if ((edge_iter->element->island == state->static_island) || (edge->element->island == state->static_island)) {
862                                 edge->flag |= STITCH_STITCHABLE;
863                                 preview->num_stitchable++;
864                                 stitch_setup_face_preview_for_uv_group(state->uvs[edge->uv1], state, island_stitch_data, preview_position);
865                                 stitch_setup_face_preview_for_uv_group(state->uvs[edge->uv2], state, island_stitch_data, preview_position);
866                                 return;
867                         }
868                 }
869         }
870
871         /* this can happen if the uvs to be stitched are not on a stitchable island */
872         if (!(edge->flag & STITCH_STITCHABLE)) {
873                 preview->num_unstitchable++;
874         }
875 }
876
877
878 static void stitch_propagate_uv_final_position(
879         Scene *scene,
880         UvElement *element, int index, PreviewPosition *preview_position,
881         UVVertAverage *final_position, StitchState *state,
882         const bool final)
883 {
884         BMesh *bm = state->em->bm;
885         StitchPreviewer *preview = state->stitch_preview;
886
887         const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
888
889         if (element->flag & STITCH_STITCHABLE) {
890                 UvElement *element_iter = element;
891                 /* propagate to coincident uvs */
892                 do {
893                         BMLoop *l;
894                         MLoopUV *luv;
895
896                         l = element_iter->l;
897                         luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
898
899                         element_iter->flag |= STITCH_PROCESSED;
900                         /* either flush to preview or to the MTFace, if final */
901                         if (final) {
902                                 copy_v2_v2(luv->uv, final_position[index].uv);
903
904                                 uvedit_uv_select_enable(state->em, scene, l, false, cd_loop_uv_offset);
905                         }
906                         else {
907                                 int face_preview_pos = preview_position[BM_elem_index_get(element_iter->l->f)].data_position;
908                                 if (face_preview_pos != STITCH_NO_PREVIEW) {
909                                         copy_v2_v2(preview->preview_polys + face_preview_pos + 2 * element_iter->tfindex,
910                                                    final_position[index].uv);
911                                 }
912                         }
913
914                         /* end of calculations, keep only the selection flag */
915                         if ((!state->snap_islands) || ((!state->midpoints) && (element_iter->island == state->static_island))) {
916                                 element_iter->flag &= STITCH_SELECTED;
917                         }
918
919                         element_iter = element_iter->next;
920                 } while (element_iter && !element_iter->separate);
921         }
922 }
923
924 /* main processing function. It calculates preview and final positions. */
925 static int stitch_process_data(StitchState *state, Scene *scene, int final)
926 {
927         int i;
928         StitchPreviewer *preview;
929         IslandStitchData *island_stitch_data = NULL;
930         int previous_island = state->static_island;
931         BMesh *bm = state->em->bm;
932         BMFace *efa;
933         BMIter iter;
934         UVVertAverage *final_position = NULL;
935
936         char stitch_midpoints = state->midpoints;
937         /* used to map uv indices to uvaverage indices for selection */
938         unsigned int *uvfinal_map = NULL;
939         /* per face preview position in preview buffer */
940         PreviewPosition *preview_position = NULL;
941
942         /* cleanup previous preview */
943         stitch_preview_delete(state->stitch_preview);
944         preview = state->stitch_preview = stitch_preview_init();
945         if (preview == NULL)
946                 return 0;
947
948         preview_position = MEM_mallocN(bm->totface * sizeof(*preview_position), "stitch_face_preview_position");
949         /* each face holds its position in the preview buffer in tmp. -1 is uninitialized */
950         for (i = 0; i < bm->totface; i++) {
951                 preview_position[i].data_position = STITCH_NO_PREVIEW;
952         }
953
954         island_stitch_data = MEM_callocN(sizeof(*island_stitch_data) * state->element_map->totalIslands, "stitch_island_data");
955         if (!island_stitch_data) {
956                 return 0;
957         }
958
959         /* store indices to editVerts and Faces. May be unneeded but ensuring anyway */
960         BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE);
961
962         /*****************************************
963          *  First determine stitchability of uvs *
964          *****************************************/
965
966         for (i = 0; i < state->selection_size; i++) {
967                 if (state->mode == STITCH_VERT) {
968                         UvElement *element = (UvElement *)state->selection_stack[i];
969                         determine_uv_stitchability(element, state, island_stitch_data);
970                 }
971                 else {
972                         UvEdge *edge = (UvEdge *)state->selection_stack[i];
973                         determine_uv_edge_stitchability(edge, state, island_stitch_data);
974                 }
975         }
976
977         /* set static island to one that is added for preview */
978         state->static_island %= state->element_map->totalIslands;
979         while (!(island_stitch_data[state->static_island].stitchableCandidate)) {
980                 state->static_island++;
981                 state->static_island %= state->element_map->totalIslands;
982                 /* this is entirely possible if for example limit stitching with no stitchable verts or no selection */
983                 if (state->static_island == previous_island)
984                         break;
985         }
986
987         for (i = 0; i < state->selection_size; i++) {
988                 if (state->mode == STITCH_VERT) {
989                         UvElement *element = (UvElement *)state->selection_stack[i];
990                         if (element->flag & STITCH_STITCHABLE_CANDIDATE) {
991                                 element->flag &= ~STITCH_STITCHABLE_CANDIDATE;
992                                 stitch_validate_uv_stitchability(element, state, island_stitch_data, preview_position);
993                         }
994                         else {
995                                 /* add to preview for unstitchable */
996                                 preview->num_unstitchable++;
997                         }
998                 }
999                 else {
1000                         UvEdge *edge = (UvEdge *)state->selection_stack[i];
1001                         if (edge->flag & STITCH_STITCHABLE_CANDIDATE) {
1002                                 edge->flag &= ~STITCH_STITCHABLE_CANDIDATE;
1003                                 stitch_validate_edge_stitchability(edge, state, island_stitch_data, preview_position);
1004                         }
1005                         else {
1006                                 preview->num_unstitchable++;
1007                         }
1008                 }
1009         }
1010
1011         /*****************************************
1012          *  Setup preview for stitchable islands *
1013          *****************************************/
1014         if (state->snap_islands) {
1015                 for (i = 0; i < state->element_map->totalIslands; i++) {
1016                         if (island_stitch_data[i].addedForPreview) {
1017                                 int numOfIslandUVs = 0, j;
1018                                 UvElement *element;
1019                                 numOfIslandUVs = getNumOfIslandUvs(state->element_map, i);
1020                                 element = &state->element_map->buf[state->element_map->islandIndices[i]];
1021                                 for (j = 0; j < numOfIslandUVs; j++, element++) {
1022                                         stitch_set_face_preview_buffer_position(element->l->f, preview, preview_position);
1023                                 }
1024                         }
1025                 }
1026         }
1027
1028         /*********************************************************************
1029          * Setup the preview buffers and fill them with the appropriate data *
1030          *********************************************************************/
1031         if (!final) {
1032                 BMIter liter;
1033                 BMLoop *l;
1034                 MLoopUV *luv;
1035                 unsigned int buffer_index = 0;
1036                 int stitchBufferIndex = 0, unstitchBufferIndex = 0;
1037                 int preview_size = (state->mode == STITCH_VERT) ? 2 : 4;
1038                 /* initialize the preview buffers */
1039                 preview->preview_polys = (float *)MEM_mallocN(preview->preview_uvs * sizeof(float) * 2, "tri_uv_stitch_prev");
1040                 preview->uvs_per_polygon = MEM_mallocN(preview->num_polys * sizeof(*preview->uvs_per_polygon), "tri_uv_stitch_prev");
1041                 preview->preview_stitchable = (float *)MEM_mallocN(preview->num_stitchable * sizeof(float) * preview_size, "stitch_preview_stitchable_data");
1042                 preview->preview_unstitchable = (float *)MEM_mallocN(preview->num_unstitchable * sizeof(float) * preview_size, "stitch_preview_unstitchable_data");
1043
1044                 preview->static_tris = (float *)MEM_mallocN(state->tris_per_island[state->static_island] * sizeof(float) * 6, "static_island_preview_tris");
1045
1046                 preview->num_static_tris = state->tris_per_island[state->static_island];
1047                 /* will cause cancel and freeing of all data structures so OK */
1048                 if (!preview->preview_polys || !preview->preview_stitchable || !preview->preview_unstitchable) {
1049                         return 0;
1050                 }
1051
1052                 /* copy data from MLoopUVs to the preview display buffers */
1053                 BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
1054                         /* just to test if face was added for processing. uvs of unselected vertices will return NULL */
1055                         UvElement *element = BM_uv_element_get(state->element_map, efa, BM_FACE_FIRST_LOOP(efa));
1056
1057                         if (element) {
1058                                 int numoftris = efa->len - 2;
1059                                 int index = BM_elem_index_get(efa);
1060                                 int face_preview_pos = preview_position[index].data_position;
1061                                 if (face_preview_pos != STITCH_NO_PREVIEW) {
1062                                         preview->uvs_per_polygon[preview_position[index].polycount_position] = efa->len;
1063                                         BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
1064                                                 luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
1065                                                 copy_v2_v2(preview->preview_polys + face_preview_pos + i * 2, luv->uv);
1066                                         }
1067                                 }
1068
1069                                 if (element->island == state->static_island) {
1070                                         BMLoop *fl = BM_FACE_FIRST_LOOP(efa);
1071                                         MLoopUV *fuv = CustomData_bmesh_get(&bm->ldata, fl->head.data, CD_MLOOPUV);
1072
1073                                         BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
1074                                                 if (i < numoftris) {
1075                                                         /* using next since the first uv is already accounted for */
1076                                                         BMLoop *lnext = l->next;
1077                                                         MLoopUV *luvnext = CustomData_bmesh_get(&bm->ldata, lnext->next->head.data, CD_MLOOPUV);
1078                                                         luv = CustomData_bmesh_get(&bm->ldata, lnext->head.data, CD_MLOOPUV);
1079
1080                                                         memcpy(preview->static_tris + buffer_index, fuv->uv, 2 * sizeof(float));
1081                                                         memcpy(preview->static_tris + buffer_index + 2, luv->uv, 2 * sizeof(float));
1082                                                         memcpy(preview->static_tris + buffer_index + 4, luvnext->uv, 2 * sizeof(float));
1083                                                         buffer_index += 6;
1084                                                 }
1085                                                 else {
1086                                                         break;
1087                                                 }
1088                                         }
1089                                 }
1090                         }
1091                 }
1092
1093                 /* fill the appropriate preview buffers */
1094                 if (state->mode == STITCH_VERT) {
1095                         for (i = 0; i < state->total_separate_uvs; i++) {
1096                                 UvElement *element = (UvElement *)state->uvs[i];
1097                                 if (element->flag & STITCH_STITCHABLE) {
1098                                         l = element->l;
1099                                         luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
1100
1101                                         copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 2], luv->uv);
1102
1103                                         stitchBufferIndex++;
1104                                 }
1105                                 else if (element->flag & STITCH_SELECTED) {
1106                                         l = element->l;
1107                                         luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
1108
1109                                         copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 2], luv->uv);
1110                                         unstitchBufferIndex++;
1111                                 }
1112                         }
1113                 }
1114                 else {
1115                         for (i = 0; i < state->total_separate_edges; i++) {
1116                                 UvEdge *edge = state->edges + i;
1117                                 UvElement *element1 = state->uvs[edge->uv1];
1118                                 UvElement *element2 = state->uvs[edge->uv2];
1119
1120                                 if (edge->flag & STITCH_STITCHABLE) {
1121                                         l = element1->l;
1122                                         luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
1123                                         copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 4], luv->uv);
1124
1125                                         l = element2->l;
1126                                         luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
1127                                         copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 4 + 2], luv->uv);
1128
1129                                         stitchBufferIndex++;
1130                                         BLI_assert(stitchBufferIndex <= preview->num_stitchable);
1131                                 }
1132                                 else if (edge->flag & STITCH_SELECTED) {
1133                                         l = element1->l;
1134                                         luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
1135                                         copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 4], luv->uv);
1136
1137                                         l = element2->l;
1138                                         luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
1139                                         copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 4 + 2], luv->uv);
1140
1141                                         unstitchBufferIndex++;
1142                                         BLI_assert(unstitchBufferIndex <= preview->num_unstitchable);
1143                                 }
1144                         }
1145                 }
1146         }
1147
1148         /******************************************************
1149          * Here we calculate the final coordinates of the uvs *
1150          ******************************************************/
1151
1152         if (state->mode == STITCH_VERT) {
1153                 final_position = MEM_callocN(state->selection_size * sizeof(*final_position), "stitch_uv_average");
1154                 uvfinal_map = MEM_mallocN(state->element_map->totalUVs * sizeof(*uvfinal_map), "stitch_uv_final_map");
1155         }
1156         else {
1157                 final_position = MEM_callocN(state->total_separate_uvs * sizeof(*final_position), "stitch_uv_average");
1158         }
1159
1160         /* first pass, calculate final position for stitchable uvs of the static island */
1161         for (i = 0; i < state->selection_size; i++) {
1162                 if (state->mode == STITCH_VERT) {
1163                         UvElement *element = state->selection_stack[i];
1164
1165                         if (element->flag & STITCH_STITCHABLE) {
1166                                 BMLoop *l;
1167                                 MLoopUV *luv;
1168                                 UvElement *element_iter;
1169
1170                                 l = element->l;
1171                                 luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
1172
1173                                 uvfinal_map[element - state->element_map->buf] = i;
1174
1175                                 copy_v2_v2(final_position[i].uv, luv->uv);
1176                                 final_position[i].count = 1;
1177
1178                                 if (state->snap_islands && element->island == state->static_island && !stitch_midpoints)
1179                                         continue;
1180
1181                                 element_iter = state->element_map->vert[BM_elem_index_get(l->v)];
1182
1183                                 for ( ; element_iter; element_iter = element_iter->next) {
1184                                         if (element_iter->separate) {
1185                                                 if (stitch_check_uvs_state_stitchable(element, element_iter, state)) {
1186                                                         l = element_iter->l;
1187                                                         luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
1188                                                         if (stitch_midpoints) {
1189                                                                 add_v2_v2(final_position[i].uv, luv->uv);
1190                                                                 final_position[i].count++;
1191                                                         }
1192                                                         else if (element_iter->island == state->static_island) {
1193                                                                 /* if multiple uvs on the static island exist,
1194                                                                  * last checked remains. to disambiguate we need to limit or use
1195                                                                  * edge stitch */
1196                                                                 copy_v2_v2(final_position[i].uv, luv->uv);
1197                                                         }
1198                                                 }
1199                                         }
1200                                 }
1201                         }
1202                         if (stitch_midpoints) {
1203                                 final_position[i].uv[0] /= final_position[i].count;
1204                                 final_position[i].uv[1] /= final_position[i].count;
1205                         }
1206                 }
1207                 else {
1208                         UvEdge *edge = state->selection_stack[i];
1209
1210                         if (edge->flag & STITCH_STITCHABLE) {
1211                                 MLoopUV *luv2, *luv1;
1212                                 BMLoop *l;
1213                                 UvEdge *edge_iter;
1214
1215                                 l = state->uvs[edge->uv1]->l;
1216                                 luv1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
1217                                 l = state->uvs[edge->uv2]->l;
1218                                 luv2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
1219
1220                                 copy_v2_v2(final_position[edge->uv1].uv, luv1->uv);
1221                                 copy_v2_v2(final_position[edge->uv2].uv, luv2->uv);
1222                                 final_position[edge->uv1].count = 1;
1223                                 final_position[edge->uv2].count = 1;
1224
1225                                 state->uvs[edge->uv1]->flag |= STITCH_STITCHABLE;
1226                                 state->uvs[edge->uv2]->flag |= STITCH_STITCHABLE;
1227
1228                                 if (state->snap_islands && edge->element->island == state->static_island && !stitch_midpoints)
1229                                         continue;
1230
1231                                 for (edge_iter = edge->first; edge_iter; edge_iter = edge_iter->next) {
1232                                         if (stitch_check_edges_state_stitchable (edge, edge_iter, state)) {
1233                                                 l = state->uvs[edge_iter->uv1]->l;
1234                                                 luv1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
1235                                                 l = state->uvs[edge_iter->uv2]->l;
1236                                                 luv2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
1237
1238                                                 if (stitch_midpoints) {
1239                                                         add_v2_v2(final_position[edge->uv1].uv, luv1->uv);
1240                                                         final_position[edge->uv1].count++;
1241                                                         add_v2_v2(final_position[edge->uv2].uv, luv2->uv);
1242                                                         final_position[edge->uv2].count++;
1243                                                 }
1244                                                 else if (edge_iter->element->island == state->static_island) {
1245                                                         copy_v2_v2(final_position[edge->uv1].uv, luv1->uv);
1246                                                         copy_v2_v2(final_position[edge->uv2].uv, luv2->uv);
1247                                                 }
1248                                         }
1249                                 }
1250                         }
1251                 }
1252         }
1253
1254         /* take mean position here. For edge case, this can't be done inside the loop for shared uvverts */
1255         if (state->mode == STITCH_EDGE && stitch_midpoints) {
1256                 for (i = 0; i < state->total_separate_uvs; i++) {
1257                         final_position[i].uv[0] /= final_position[i].count;
1258                         final_position[i].uv[1] /= final_position[i].count;
1259                 }
1260         }
1261
1262         /* second pass, calculate island rotation and translation before modifying any uvs */
1263         if (state->snap_islands) {
1264                 if (state->mode == STITCH_VERT) {
1265                         for (i = 0; i < state->selection_size; i++) {
1266                                 UvElement *element = state->selection_stack[i];
1267
1268                                 if (element->flag & STITCH_STITCHABLE) {
1269                                         BMLoop *l;
1270                                         MLoopUV *luv;
1271
1272                                         l = element->l;
1273                                         luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
1274
1275                                         /* accumulate each islands' translation from stitchable elements. it is important to do here
1276                                          * because in final pass MTFaces get modified and result is zero. */
1277                                         island_stitch_data[element->island].translation[0] += final_position[i].uv[0] - luv->uv[0];
1278                                         island_stitch_data[element->island].translation[1] += final_position[i].uv[1] - luv->uv[1];
1279                                         island_stitch_data[element->island].medianPoint[0] += luv->uv[0];
1280                                         island_stitch_data[element->island].medianPoint[1] += luv->uv[1];
1281                                         island_stitch_data[element->island].numOfElements++;
1282                                 }
1283                         }
1284
1285                         /* only calculate rotation when an edge has been fully selected */
1286                         for (i = 0; i < state->total_separate_edges; i++) {
1287                                 UvEdge *edge = state->edges + i;
1288                                 if ((edge->flag & STITCH_BOUNDARY) &&
1289                                     (state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) &&
1290                                     (state->uvs[edge->uv2]->flag & STITCH_STITCHABLE))
1291                                 {
1292                                         stitch_island_calculate_edge_rotation(edge, state, final_position, uvfinal_map, island_stitch_data);
1293                                         island_stitch_data[state->uvs[edge->uv1]->island].use_edge_rotation = true;
1294                                 }
1295                         }
1296
1297                         /* clear seams of stitched edges */
1298                         if (final && state->clear_seams) {
1299                                 for (i = 0; i < state->total_separate_edges; i++) {
1300                                         UvEdge *edge = state->edges + i;
1301                                         if ((state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) &&
1302                                             (state->uvs[edge->uv2]->flag & STITCH_STITCHABLE))
1303                                         {
1304                                                 BM_elem_flag_disable(edge->element->l->e, BM_ELEM_SEAM);
1305                                         }
1306                                 }
1307                         }
1308
1309                         for (i = 0; i < state->selection_size; i++) {
1310                                 UvElement *element = state->selection_stack[i];
1311                                 if (!island_stitch_data[element->island].use_edge_rotation) {
1312                                         if (element->flag & STITCH_STITCHABLE) {
1313                                                 stitch_island_calculate_vert_rotation(element, state, island_stitch_data);
1314                                         }
1315                                 }
1316                         }
1317                 }
1318                 else {
1319                         for (i = 0; i < state->total_separate_uvs; i++) {
1320                                 UvElement *element = state->uvs[i];
1321
1322                                 if (element->flag & STITCH_STITCHABLE) {
1323                                         BMLoop *l;
1324                                         MLoopUV *luv;
1325
1326                                         l = element->l;
1327                                         luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
1328
1329                                         /* accumulate each islands' translation from stitchable elements. it is important to do here
1330                                          * because in final pass MTFaces get modified and result is zero. */
1331                                         island_stitch_data[element->island].translation[0] += final_position[i].uv[0] - luv->uv[0];
1332                                         island_stitch_data[element->island].translation[1] += final_position[i].uv[1] - luv->uv[1];
1333                                         island_stitch_data[element->island].medianPoint[0] += luv->uv[0];
1334                                         island_stitch_data[element->island].medianPoint[1] += luv->uv[1];
1335                                         island_stitch_data[element->island].numOfElements++;
1336                                 }
1337                         }
1338
1339                         for (i = 0; i < state->selection_size; i++) {
1340                                 UvEdge *edge = state->selection_stack[i];
1341
1342                                 if (edge->flag & STITCH_STITCHABLE) {
1343                                         stitch_island_calculate_edge_rotation(edge, state, final_position, NULL, island_stitch_data);
1344                                         island_stitch_data[state->uvs[edge->uv1]->island].use_edge_rotation = true;
1345                                 }
1346                         }
1347
1348                         /* clear seams of stitched edges */
1349                         if (final && state->clear_seams) {
1350                                 for (i = 0; i < state->selection_size; i++) {
1351                                         UvEdge *edge = state->selection_stack[i];
1352                                         if (edge->flag & STITCH_STITCHABLE) {
1353                                                 BM_elem_flag_disable(edge->element->l->e, BM_ELEM_SEAM);
1354                                         }
1355                                 }
1356                         }
1357                 }
1358         }
1359
1360         /* third pass, propagate changes to coincident uvs */
1361         for (i = 0; i < state->selection_size; i++) {
1362                 if (state->mode == STITCH_VERT) {
1363                         UvElement *element = state->selection_stack[i];
1364
1365                         stitch_propagate_uv_final_position(scene, element, i, preview_position, final_position, state, final);
1366                 }
1367                 else {
1368                         UvEdge *edge = state->selection_stack[i];
1369
1370                         stitch_propagate_uv_final_position(
1371                                 scene, state->uvs[edge->uv1], edge->uv1, preview_position, final_position, state, final);
1372                         stitch_propagate_uv_final_position(
1373                                 scene, state->uvs[edge->uv2], edge->uv2, preview_position, final_position, state, final);
1374
1375                         edge->flag &= (STITCH_SELECTED | STITCH_BOUNDARY);
1376                 }
1377         }
1378
1379         /* final pass, calculate Island translation/rotation if needed */
1380         if (state->snap_islands) {
1381                 stitch_calculate_island_snapping(state, preview_position, preview, island_stitch_data, final);
1382         }
1383
1384         MEM_freeN(final_position);
1385         if (state->mode == STITCH_VERT) {
1386                 MEM_freeN(uvfinal_map);
1387         }
1388         MEM_freeN(island_stitch_data);
1389         MEM_freeN(preview_position);
1390
1391         return 1;
1392 }
1393
1394 /* Stitch hash initialization functions */
1395 static unsigned int uv_edge_hash(const void *key)
1396 {
1397         const UvEdge *edge = key;
1398         return (BLI_ghashutil_uinthash(edge->uv2) +
1399                 BLI_ghashutil_uinthash(edge->uv1));
1400 }
1401
1402 static bool uv_edge_compare(const void *a, const void *b)
1403 {
1404         const UvEdge *edge1 = a;
1405         const UvEdge *edge2 = b;
1406
1407         if ((edge1->uv1 == edge2->uv1) && (edge1->uv2 == edge2->uv2)) {
1408                 return 0;
1409         }
1410         return 1;
1411 }
1412
1413 /* select all common edges */
1414 static void stitch_select_edge(UvEdge *edge, StitchState *state, int always_select)
1415 {
1416         UvEdge *eiter;
1417         UvEdge **selection_stack = (UvEdge **)state->selection_stack;
1418
1419         for (eiter = edge->first; eiter; eiter = eiter->next) {
1420                 if (eiter->flag & STITCH_SELECTED) {
1421                         int i;
1422                         if (always_select)
1423                                 continue;
1424
1425                         eiter->flag &= ~STITCH_SELECTED;
1426                         for (i = 0; i < state->selection_size; i++) {
1427                                 if (selection_stack[i] == eiter) {
1428                                         (state->selection_size)--;
1429                                         selection_stack[i] = selection_stack[state->selection_size];
1430                                         break;
1431                                 }
1432                         }
1433                 }
1434                 else {
1435                         eiter->flag |= STITCH_SELECTED;
1436                         selection_stack[state->selection_size++] = eiter;
1437                 }
1438         }
1439 }
1440
1441
1442 /* Select all common uvs */
1443 static void stitch_select_uv(UvElement *element, StitchState *state, int always_select)
1444 {
1445         BMLoop *l;
1446         UvElement *element_iter;
1447         UvElement **selection_stack = (UvElement **)state->selection_stack;
1448
1449         l = element->l;
1450
1451         element_iter = state->element_map->vert[BM_elem_index_get(l->v)];
1452         /* first deselect all common uvs */
1453         for (; element_iter; element_iter = element_iter->next) {
1454                 if (element_iter->separate) {
1455                         /* only separators go to selection */
1456                         if (element_iter->flag & STITCH_SELECTED) {
1457                                 int i;
1458                                 if (always_select)
1459                                         continue;
1460
1461                                 element_iter->flag &= ~STITCH_SELECTED;
1462                                 for (i = 0; i < state->selection_size; i++) {
1463                                         if (selection_stack[i] == element_iter) {
1464                                                 (state->selection_size)--;
1465                                                 selection_stack[i] = selection_stack[state->selection_size];
1466                                                 break;
1467                                         }
1468                                 }
1469                         }
1470                         else {
1471                                 element_iter->flag |= STITCH_SELECTED;
1472                                 selection_stack[state->selection_size++] = element_iter;
1473                         }
1474                 }
1475         }
1476 }
1477
1478 static void stitch_switch_selection_mode(StitchState *state)
1479 {
1480         void **old_selection_stack = state->selection_stack;
1481         int old_selection_size = state->selection_size;
1482         state->selection_size = 0;
1483
1484         if (state->mode == STITCH_VERT) {
1485                 int i;
1486                 state->selection_stack = MEM_mallocN(state->total_separate_edges * sizeof(*state->selection_stack),
1487                                                      "stitch_new_edge_selection_stack");
1488
1489                 /* check if both elements of an edge are selected */
1490                 for (i = 0; i < state->total_separate_edges; i++) {
1491                         UvEdge *edge = state->edges + i;
1492                         UvElement *element1 = state->uvs[edge->uv1];
1493                         UvElement *element2 = state->uvs[edge->uv2];
1494
1495                         if ((element1->flag & STITCH_SELECTED) && (element2->flag & STITCH_SELECTED))
1496                                 stitch_select_edge(edge, state, true);
1497                 }
1498
1499                 /* unselect selected uvelements */
1500                 for (i = 0; i < old_selection_size; i++) {
1501                         UvElement *element = old_selection_stack[i];
1502
1503                         element->flag &= ~STITCH_SELECTED;
1504                 }
1505                 state->mode = STITCH_EDGE;
1506         }
1507         else {
1508                 int i;
1509                 state->selection_stack = MEM_mallocN(state->total_separate_uvs * sizeof(*state->selection_stack),
1510                                                      "stitch_new_vert_selection_stack");
1511
1512                 for (i = 0; i < old_selection_size; i++) {
1513                         UvEdge *edge = old_selection_stack[i];
1514                         UvElement *element1 = state->uvs[edge->uv1];
1515                         UvElement *element2 = state->uvs[edge->uv2];
1516
1517                         stitch_select_uv(element1, state, true);
1518                         stitch_select_uv(element2, state, true);
1519
1520                         edge->flag &= ~STITCH_SELECTED;
1521                 }
1522                 state->mode = STITCH_VERT;
1523         }
1524         MEM_freeN(old_selection_stack);
1525 }
1526
1527 static void stitch_calculate_edge_normal(BMEditMesh *em, UvEdge *edge, float *normal, float aspect)
1528 {
1529         BMLoop *l1 = edge->element->l;
1530         MLoopUV *luv1, *luv2;
1531         float tangent[2];
1532
1533         luv1 = CustomData_bmesh_get(&em->bm->ldata, l1->head.data, CD_MLOOPUV);
1534         luv2 = CustomData_bmesh_get(&em->bm->ldata, l1->next->head.data, CD_MLOOPUV);
1535
1536         sub_v2_v2v2(tangent, luv2->uv,  luv1->uv);
1537
1538         tangent[1] /= aspect;
1539
1540         normal[0] = tangent[1];
1541         normal[1] = -tangent[0];
1542
1543         normalize_v2(normal);
1544 }
1545
1546 /**
1547  */
1548 static void stitch_draw_vbo(Gwn_VertBuf *vbo, Gwn_PrimType prim_type, const float col[4])
1549 {
1550         Gwn_Batch *batch = GWN_batch_create_ex(prim_type, vbo, NULL, GWN_BATCH_OWNS_VBO);
1551         GWN_batch_program_set_builtin(batch, GPU_SHADER_2D_UNIFORM_COLOR);
1552         GWN_batch_uniform_4fv(batch, "color", col);
1553         GWN_batch_draw(batch);
1554         GWN_batch_discard(batch);
1555 }
1556
1557 /* TODO make things pretier : store batches inside StitchPreviewer instead of the bare verts pos */
1558 static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
1559 {
1560         int j, index = 0;
1561         unsigned int num_line = 0, num_tri, tri_idx = 0, line_idx = 0;
1562         StitchState *state = (StitchState *)arg;
1563         StitchPreviewer *stitch_preview = state->stitch_preview;
1564         Gwn_VertBuf *vbo, *vbo_line;
1565         float col[4];
1566
1567         static Gwn_VertFormat format = { 0 };
1568         static unsigned int pos_id;
1569         if (format.attrib_ct == 0) {
1570                 pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
1571         }
1572
1573         glEnable(GL_BLEND);
1574
1575         /* Static Tris */
1576         UI_GetThemeColor4fv(TH_STITCH_PREVIEW_ACTIVE, col);
1577         vbo = GWN_vertbuf_create_with_format(&format);
1578         GWN_vertbuf_data_alloc(vbo, stitch_preview->num_static_tris * 3);
1579         for (int i = 0; i < stitch_preview->num_static_tris * 3; i++) {
1580                 GWN_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->static_tris[i * 2]);
1581         }
1582         stitch_draw_vbo(vbo, GWN_PRIM_TRIS, col);
1583
1584
1585         /* Preview Polys */
1586         for (int i = 0; i < stitch_preview->num_polys; i++)
1587                 num_line += stitch_preview->uvs_per_polygon[i];
1588
1589         num_tri = num_line - 2 * stitch_preview->num_polys;
1590
1591         /* we need to convert the polys into triangles / lines */
1592         vbo = GWN_vertbuf_create_with_format(&format);
1593         vbo_line = GWN_vertbuf_create_with_format(&format);
1594
1595         GWN_vertbuf_data_alloc(vbo, num_tri * 3);
1596         GWN_vertbuf_data_alloc(vbo_line, num_line * 2);
1597
1598         for (int i = 0; i < stitch_preview->num_polys; i++) {
1599                 BLI_assert(stitch_preview->uvs_per_polygon[i] >= 3);
1600
1601                 /* Start line */
1602                 GWN_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index]);
1603                 GWN_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + 2]);
1604
1605                 for (j = 1; j < stitch_preview->uvs_per_polygon[i] - 1; ++j) {
1606                         GWN_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index]);
1607                         GWN_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index + (j + 0) * 2]);
1608                         GWN_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index + (j + 1) * 2]);
1609
1610                         GWN_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + (j + 0) * 2]);
1611                         GWN_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + (j + 1) * 2]);
1612                 }
1613
1614                 /* Closing line */
1615                 GWN_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index]);
1616                 /* j = uvs_per_polygon[i] - 1*/
1617                 GWN_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + j * 2]);
1618
1619                 index += stitch_preview->uvs_per_polygon[i] * 2;
1620         }
1621         UI_GetThemeColor4fv(TH_STITCH_PREVIEW_FACE, col);
1622         stitch_draw_vbo(vbo, GWN_PRIM_TRIS, col);
1623         UI_GetThemeColor4fv(TH_STITCH_PREVIEW_EDGE, col);
1624         stitch_draw_vbo(vbo_line, GWN_PRIM_LINES, col);
1625
1626         glDisable(GL_BLEND);
1627
1628
1629         /* draw stitch vert/lines preview */
1630         if (state->mode == STITCH_VERT) {
1631                 glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) * 2.0f);
1632
1633                 UI_GetThemeColor4fv(TH_STITCH_PREVIEW_STITCHABLE, col);
1634                 vbo = GWN_vertbuf_create_with_format(&format);
1635                 GWN_vertbuf_data_alloc(vbo, stitch_preview->num_stitchable);
1636                 for (int i = 0; i < stitch_preview->num_stitchable; i++) {
1637                         GWN_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_stitchable[i * 2]);
1638                 }
1639                 stitch_draw_vbo(vbo, GWN_PRIM_POINTS, col);
1640
1641                 UI_GetThemeColor4fv(TH_STITCH_PREVIEW_UNSTITCHABLE, col);
1642                 vbo = GWN_vertbuf_create_with_format(&format);
1643                 GWN_vertbuf_data_alloc(vbo, stitch_preview->num_unstitchable);
1644                 for (int i = 0; i < stitch_preview->num_unstitchable; i++) {
1645                         GWN_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_unstitchable[i * 2]);
1646                 }
1647                 stitch_draw_vbo(vbo, GWN_PRIM_POINTS, col);
1648         }
1649         else {
1650                 UI_GetThemeColor4fv(TH_STITCH_PREVIEW_STITCHABLE, col);
1651                 vbo = GWN_vertbuf_create_with_format(&format);
1652                 GWN_vertbuf_data_alloc(vbo, stitch_preview->num_stitchable * 2);
1653                 for (int i = 0; i < stitch_preview->num_stitchable * 2; i++) {
1654                         GWN_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_stitchable[i * 2]);
1655                 }
1656                 stitch_draw_vbo(vbo, GWN_PRIM_LINES, col);
1657
1658                 UI_GetThemeColor4fv(TH_STITCH_PREVIEW_UNSTITCHABLE, col);
1659                 vbo = GWN_vertbuf_create_with_format(&format);
1660                 GWN_vertbuf_data_alloc(vbo, stitch_preview->num_unstitchable * 2);
1661                 for (int i = 0; i < stitch_preview->num_unstitchable * 2; i++) {
1662                         GWN_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_unstitchable[i * 2]);
1663                 }
1664                 stitch_draw_vbo(vbo, GWN_PRIM_LINES, col);
1665         }
1666 }
1667
1668 static UvEdge *uv_edge_get(BMLoop *l, StitchState *state)
1669 {
1670         UvEdge tmp_edge;
1671
1672         UvElement *element1 = BM_uv_element_get(state->element_map, l->f, l);
1673         UvElement *element2 = BM_uv_element_get(state->element_map, l->f, l->next);
1674
1675         int uv1 = state->map[element1 - state->element_map->buf];
1676         int uv2 = state->map[element2 - state->element_map->buf];
1677
1678         if (uv1 < uv2) {
1679                 tmp_edge.uv1 = uv1;
1680                 tmp_edge.uv2 = uv2;
1681         }
1682         else {
1683                 tmp_edge.uv1 = uv2;
1684                 tmp_edge.uv2 = uv1;
1685         }
1686
1687         return BLI_ghash_lookup(state->edge_hash, &tmp_edge);
1688 }
1689
1690 static int stitch_init(bContext *C, wmOperator *op)
1691 {
1692         /* for fast edge lookup... */
1693         GHash *edge_hash;
1694         /* ...and actual edge storage */
1695         UvEdge *edges;
1696         int total_edges;
1697         /* maps uvelements to their first coincident uv */
1698         int *map;
1699         int counter = 0, i;
1700         BMFace *efa;
1701         BMLoop *l;
1702         BMIter iter, liter;
1703         GHashIterator gh_iter;
1704         UvEdge *all_edges;
1705         StitchState *state;
1706         Scene *scene = CTX_data_scene(C);
1707         ToolSettings *ts = scene->toolsettings;
1708         ARegion *ar = CTX_wm_region(C);
1709         float aspx, aspy;
1710         Object *obedit = CTX_data_edit_object(C);
1711         BMEditMesh *em = BKE_editmesh_from_object(obedit);
1712         const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1713
1714         if (!ar)
1715                 return 0;
1716
1717         state = MEM_callocN(sizeof(StitchState), "stitch state");
1718
1719         op->customdata = state;
1720
1721         /* initialize state */
1722         state->use_limit = RNA_boolean_get(op->ptr, "use_limit");
1723         state->limit_dist = RNA_float_get(op->ptr, "limit");
1724         state->obedit = obedit;
1725         state->em = em;
1726         state->snap_islands = RNA_boolean_get(op->ptr, "snap_islands");
1727         state->static_island = RNA_int_get(op->ptr, "static_island");
1728         state->midpoints = RNA_boolean_get(op->ptr, "midpoint_snap");
1729         state->clear_seams = RNA_boolean_get(op->ptr, "clear_seams");
1730         if (RNA_struct_property_is_set(op->ptr, "mode")) {
1731                 state->mode = RNA_enum_get(op->ptr, "mode");
1732         }
1733         else {
1734                 if (ts->uv_flag & UV_SYNC_SELECTION) {
1735                         if (ts->selectmode & SCE_SELECT_VERTEX)
1736                                 state->mode = STITCH_VERT;
1737                         else
1738                                 state->mode = STITCH_EDGE;
1739                 }
1740                 else {
1741                         if (ts->uv_selectmode & UV_SELECT_VERTEX) {
1742                                 state->mode = STITCH_VERT;
1743                         }
1744                         else {
1745                                 state->mode = STITCH_EDGE;
1746                         }
1747                 }
1748         }
1749
1750         /* in uv synch selection, all uv's are visible */
1751         if (ts->uv_flag & UV_SYNC_SELECTION) {
1752                 state->element_map = BM_uv_element_map_create(state->em->bm, false, true, true);
1753         }
1754         else {
1755                 state->element_map = BM_uv_element_map_create(state->em->bm, true, true, true);
1756         }
1757         if (!state->element_map) {
1758                 state_delete(state);
1759                 return 0;
1760         }
1761
1762         ED_uvedit_get_aspect(scene, obedit, em->bm, &aspx, &aspy);
1763         state->aspect = aspx / aspy;
1764
1765         /* Entirely possible if redoing last operator that static island is bigger than total number of islands.
1766          * This ensures we get no hang in the island checking code in stitch_stitch_process_data. */
1767         state->static_island %= state->element_map->totalIslands;
1768
1769         /* Count 'unique' uvs */
1770         for (i = 0; i < state->element_map->totalUVs; i++) {
1771                 if (state->element_map->buf[i].separate) {
1772                         counter++;
1773                 }
1774         }
1775
1776         /* explicitly set preview to NULL, to avoid deleting an invalid pointer on stitch_process_data */
1777         state->stitch_preview = NULL;
1778         /* Allocate the unique uv buffers */
1779         state->uvs = MEM_mallocN(sizeof(*state->uvs) * counter, "uv_stitch_unique_uvs");
1780         /* internal uvs need no normals but it is hard and slow to keep a map of
1781          * normals only for boundary uvs, so allocating for all uvs */
1782         state->normals = MEM_callocN(sizeof(*state->normals) * counter * 2, "uv_stitch_normals");
1783         state->total_separate_uvs = counter;
1784         state->map = map = MEM_mallocN(sizeof(*map) * state->element_map->totalUVs, "uv_stitch_unique_map");
1785         /* Allocate the edge stack */
1786         edge_hash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "stitch_edge_hash");
1787         all_edges = MEM_mallocN(sizeof(*all_edges) * state->element_map->totalUVs, "stitch_all_edges");
1788
1789         if (!state->uvs || !map || !edge_hash || !all_edges) {
1790                 state_delete(state);
1791                 return 0;
1792         }
1793
1794         /* So that we can use this as index for the UvElements */
1795         counter = -1;
1796         /* initialize the unique UVs and map */
1797         for (i = 0; i < em->bm->totvert; i++) {
1798                 UvElement *element = state->element_map->vert[i];
1799                 for (; element; element = element->next) {
1800                         if (element->separate) {
1801                                 counter++;
1802                                 state->uvs[counter] = element;
1803                         }
1804                         /* pointer arithmetic to the rescue, as always :)*/
1805                         map[element - state->element_map->buf] = counter;
1806                 }
1807         }
1808
1809         counter = 0;
1810         /* Now, on to generate our uv connectivity data */
1811         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1812                 if (!(ts->uv_flag & UV_SYNC_SELECTION) &&
1813                     ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || !BM_elem_flag_test(efa, BM_ELEM_SELECT)))
1814                 {
1815                         continue;
1816                 }
1817
1818                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1819                         UvElement *element = BM_uv_element_get(state->element_map, efa, l);
1820                         int offset1, itmp1 = element - state->element_map->buf;
1821                         int offset2, itmp2 = BM_uv_element_get(state->element_map, efa, l->next) - state->element_map->buf;
1822                         UvEdge *edge;
1823
1824                         offset1 = map[itmp1];
1825                         offset2 = map[itmp2];
1826
1827                         all_edges[counter].next = NULL;
1828                         all_edges[counter].first = NULL;
1829                         all_edges[counter].flag = 0;
1830                         all_edges[counter].element = element;
1831                         /* using an order policy, sort uvs according to address space. This avoids
1832                          * Having two different UvEdges with the same uvs on different positions  */
1833                         if (offset1 < offset2) {
1834                                 all_edges[counter].uv1 = offset1;
1835                                 all_edges[counter].uv2 = offset2;
1836                         }
1837                         else {
1838                                 all_edges[counter].uv1 = offset2;
1839                                 all_edges[counter].uv2 = offset1;
1840                         }
1841
1842                         edge = BLI_ghash_lookup(edge_hash, &all_edges[counter]);
1843                         if (edge) {
1844                                 edge->flag = 0;
1845                         }
1846                         else {
1847                                 BLI_ghash_insert(edge_hash, &all_edges[counter], &all_edges[counter]);
1848                                 all_edges[counter].flag = STITCH_BOUNDARY;
1849                         }
1850                         counter++;
1851                 }
1852         }
1853
1854         total_edges = BLI_ghash_len(edge_hash);
1855         state->edges = edges = MEM_mallocN(sizeof(*edges) * total_edges, "stitch_edges");
1856
1857         /* I assume any system will be able to at least allocate an iterator :p */
1858         if (!edges) {
1859                 state_delete(state);
1860                 return 0;
1861         }
1862
1863         state->total_separate_edges = total_edges;
1864
1865         /* fill the edges with data */
1866         i = 0;
1867         GHASH_ITER (gh_iter, edge_hash) {
1868                 edges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter));
1869         }
1870
1871         /* cleanup temporary stuff */
1872         MEM_freeN(all_edges);
1873
1874         BLI_ghash_free(edge_hash, NULL, NULL);
1875
1876         /* refill an edge hash to create edge connnectivity data */
1877         state->edge_hash = edge_hash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "stitch_edge_hash");
1878         for (i = 0; i < total_edges; i++) {
1879                 BLI_ghash_insert(edge_hash, edges + i, edges + i);
1880         }
1881         stitch_uv_edge_generate_linked_edges(edge_hash, state);
1882
1883         /***** calculate 2D normals for boundary uvs *****/
1884
1885         /* we use boundary edges to calculate 2D normals.
1886          * to disambiguate the direction of the normal, we also need
1887          * a point "inside" the island, that can be provided by
1888          * the winding of the polygon (assuming counter-clockwise flow). */
1889
1890         for (i = 0; i < total_edges; i++) {
1891                 UvEdge *edge = edges + i;
1892                 float normal[2];
1893                 if (edge->flag & STITCH_BOUNDARY) {
1894                         stitch_calculate_edge_normal(em, edge, normal, state->aspect);
1895
1896                         add_v2_v2(state->normals + edge->uv1 * 2, normal);
1897                         add_v2_v2(state->normals + edge->uv2 * 2, normal);
1898
1899                         normalize_v2(state->normals + edge->uv1 * 2);
1900                         normalize_v2(state->normals + edge->uv2 * 2);
1901                 }
1902         }
1903
1904
1905         /***** fill selection stack *******/
1906
1907         state->selection_size = 0;
1908
1909         /* Load old selection if redoing operator with different settings */
1910         if (RNA_struct_property_is_set(op->ptr, "selection")) {
1911                 int faceIndex, elementIndex;
1912                 UvElement *element;
1913                 enum StitchModes stored_mode = RNA_enum_get(op->ptr, "stored_mode");
1914
1915                 BM_mesh_elem_table_ensure(em->bm, BM_FACE);
1916
1917                 if (stored_mode == STITCH_VERT) {
1918                         state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_uvs, "uv_stitch_selection_stack");
1919
1920                         RNA_BEGIN (op->ptr, itemptr, "selection")
1921                         {
1922                                 faceIndex = RNA_int_get(&itemptr, "face_index");
1923                                 elementIndex = RNA_int_get(&itemptr, "element_index");
1924                                 efa = BM_face_at_index(em->bm, faceIndex);
1925                                 element = BM_uv_element_get(state->element_map, efa, BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex));
1926                                 stitch_select_uv(element, state, 1);
1927                         }
1928                         RNA_END;
1929                 }
1930                 else {
1931                         state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_edges, "uv_stitch_selection_stack");
1932
1933                         RNA_BEGIN (op->ptr, itemptr, "selection")
1934                         {
1935                                 UvEdge tmp_edge, *edge;
1936                                 int uv1, uv2;
1937                                 faceIndex = RNA_int_get(&itemptr, "face_index");
1938                                 elementIndex = RNA_int_get(&itemptr, "element_index");
1939                                 efa = BM_face_at_index(em->bm, faceIndex);
1940                                 element = BM_uv_element_get(state->element_map, efa, BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex));
1941                                 uv1 = map[element - state->element_map->buf];
1942
1943                                 element = BM_uv_element_get(state->element_map, efa, BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, (elementIndex + 1) % efa->len));
1944                                 uv2 = map[element - state->element_map->buf];
1945
1946                                 if (uv1 < uv2) {
1947                                         tmp_edge.uv1 = uv1;
1948                                         tmp_edge.uv2 = uv2;
1949                                 }
1950                                 else {
1951                                         tmp_edge.uv1 = uv2;
1952                                         tmp_edge.uv2 = uv1;
1953                                 }
1954
1955                                 edge = BLI_ghash_lookup(edge_hash, &tmp_edge);
1956
1957                                 stitch_select_edge(edge, state, true);
1958                         }
1959                         RNA_END;
1960                 }
1961                 /* if user has switched the operator mode after operation, we need to convert
1962                  * the stored format */
1963                 if (state->mode != stored_mode) {
1964                         state->mode = stored_mode;
1965                         stitch_switch_selection_mode(state);
1966                 }
1967                 /* Clear the selection */
1968                 RNA_collection_clear(op->ptr, "selection");
1969
1970         }
1971         else {
1972                 if (state->mode == STITCH_VERT) {
1973                         state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_uvs, "uv_stitch_selection_stack");
1974
1975                         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1976                                 BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
1977                                         if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1978                                                 UvElement *element = BM_uv_element_get(state->element_map, efa, l);
1979                                                 if (element) {
1980                                                         stitch_select_uv(element, state, 1);
1981                                                 }
1982                                         }
1983                                 }
1984                         }
1985                 }
1986                 else {
1987                         state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_edges, "uv_stitch_selection_stack");
1988
1989                         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1990                                 if (!(ts->uv_flag & UV_SYNC_SELECTION) &&
1991                                     ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || !BM_elem_flag_test(efa, BM_ELEM_SELECT)))
1992                                 {
1993                                         continue;
1994                                 }
1995
1996                                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1997                                         if (uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) {
1998                                                 UvEdge *edge = uv_edge_get(l, state);
1999                                                 if (edge) {
2000                                                         stitch_select_edge(edge, state, true);
2001                                                 }
2002                                         }
2003                                 }
2004                         }
2005                 }
2006         }
2007
2008         /***** initialize static island preview data *****/
2009
2010         state->tris_per_island = MEM_mallocN(sizeof(*state->tris_per_island) * state->element_map->totalIslands,
2011                                              "stitch island tris");
2012         for (i = 0; i < state->element_map->totalIslands; i++) {
2013                 state->tris_per_island[i] = 0;
2014         }
2015
2016         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2017                 UvElement *element = BM_uv_element_get(state->element_map, efa, BM_FACE_FIRST_LOOP(efa));
2018
2019                 if (element) {
2020                         state->tris_per_island[element->island] += (efa->len > 2) ? efa->len - 2 : 0;
2021                 }
2022         }
2023
2024         if (!stitch_process_data(state, scene, false)) {
2025
2026                 state_delete(state);
2027                 return 0;
2028         }
2029
2030         state->draw_handle = ED_region_draw_cb_activate(ar->type, stitch_draw, state, REGION_DRAW_POST_VIEW);
2031
2032         stitch_update_header(state, C);
2033         return 1;
2034 }
2035
2036 static int stitch_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2037 {
2038         Object *obedit = CTX_data_edit_object(C);
2039         if (!stitch_init(C, op))
2040                 return OPERATOR_CANCELLED;
2041
2042         WM_event_add_modal_handler(C, op);
2043         WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
2044         return OPERATOR_RUNNING_MODAL;
2045 }
2046
2047 static void stitch_exit(bContext *C, wmOperator *op, int finished)
2048 {
2049         StitchState *state;
2050         Scene *scene;
2051         SpaceImage *sima;
2052         ScrArea *sa = CTX_wm_area(C);
2053         Object *obedit;
2054
2055         scene = CTX_data_scene(C);
2056         obedit = CTX_data_edit_object(C);
2057         sima = CTX_wm_space_image(C);
2058
2059         state = (StitchState *)op->customdata;
2060
2061         if (finished) {
2062                 int i;
2063
2064                 RNA_float_set(op->ptr, "limit", state->limit_dist);
2065                 RNA_boolean_set(op->ptr, "use_limit", state->use_limit);
2066                 RNA_boolean_set(op->ptr, "snap_islands", state->snap_islands);
2067                 RNA_int_set(op->ptr, "static_island", state->static_island);
2068                 RNA_boolean_set(op->ptr, "midpoint_snap", state->midpoints);
2069                 RNA_enum_set(op->ptr, "mode", state->mode);
2070                 RNA_enum_set(op->ptr, "stored_mode", state->mode);
2071
2072                 /* Store selection for re-execution of stitch */
2073                 for (i = 0; i < state->selection_size; i++) {
2074                         UvElement *element;
2075                         PointerRNA itemptr;
2076                         if (state->mode == STITCH_VERT) {
2077                                 element = state->selection_stack[i];
2078                         }
2079                         else {
2080                                 element = ((UvEdge *)state->selection_stack[i])->element;
2081                         }
2082                         RNA_collection_add(op->ptr, "selection", &itemptr);
2083
2084                         RNA_int_set(&itemptr, "face_index", BM_elem_index_get(element->l->f));
2085                         RNA_int_set(&itemptr, "element_index", element->tfindex);
2086                 }
2087
2088                 uvedit_live_unwrap_update(sima, scene, obedit);
2089         }
2090
2091         if (sa)
2092                 ED_area_headerprint(sa, NULL);
2093
2094         ED_region_draw_cb_exit(CTX_wm_region(C)->type, state->draw_handle);
2095
2096         DEG_id_tag_update(obedit->data, 0);
2097         WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
2098
2099         state_delete(state);
2100         op->customdata = NULL;
2101 }
2102
2103
2104 static void stitch_cancel(bContext *C, wmOperator *op)
2105 {
2106         stitch_exit(C, op, 0);
2107 }
2108
2109
2110 static int stitch_exec(bContext *C, wmOperator *op)
2111 {
2112         Scene *scene = CTX_data_scene(C);
2113
2114         if (!stitch_init(C, op))
2115                 return OPERATOR_CANCELLED;
2116         if (stitch_process_data((StitchState *)op->customdata, scene, 1)) {
2117                 stitch_exit(C, op, 1);
2118                 return OPERATOR_FINISHED;
2119         }
2120         else {
2121                 stitch_cancel(C, op);
2122                 return OPERATOR_CANCELLED;
2123         }
2124 }
2125
2126 static void stitch_select(bContext *C, Scene *scene, const wmEvent *event, StitchState *state)
2127 {
2128         /* add uv under mouse to processed uv's */
2129         float co[2];
2130         UvNearestHit hit = UV_NEAREST_HIT_INIT;
2131         ARegion *ar = CTX_wm_region(C);
2132         Image *ima = CTX_data_edit_image(C);
2133
2134         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
2135
2136         if (state->mode == STITCH_VERT) {
2137                 if (uv_find_nearest_vert(
2138                             scene, ima, state->obedit, co, 0.0f, &hit))
2139                 {
2140                         /* Add vertex to selection, deselect all common uv's of vert other
2141                          * than selected and update the preview. This behavior was decided so that
2142                          * you can do stuff like deselect the opposite stitchable vertex and the initial still gets deselected */
2143
2144                         /* This works due to setting of tmp in find nearest uv vert */
2145                         UvElement *element = BM_uv_element_get(state->element_map, hit.efa, hit.l);
2146                         stitch_select_uv(element, state, false);
2147
2148                 }
2149         }
2150         else {
2151                 if (uv_find_nearest_edge(
2152                             scene, ima, state->obedit, co, &hit))
2153                 {
2154                         UvEdge *edge = uv_edge_get(hit.l, state);
2155                         stitch_select_edge(edge, state, false);
2156                 }
2157         }
2158 }
2159
2160 static int stitch_modal(bContext *C, wmOperator *op, const wmEvent *event)
2161 {
2162         StitchState *state;
2163         Scene *scene = CTX_data_scene(C);
2164
2165         state = (StitchState *)op->customdata;
2166
2167         switch (event->type) {
2168                 case MIDDLEMOUSE:
2169                         return OPERATOR_PASS_THROUGH;
2170
2171                         /* Cancel */
2172                 case ESCKEY:
2173                         stitch_cancel(C, op);
2174                         return OPERATOR_CANCELLED;
2175
2176                 case LEFTMOUSE:
2177                         if (event->shift && (U.flag & USER_LMOUSESELECT)) {
2178                                 if (event->val == KM_PRESS) {
2179                                         stitch_select(C, scene, event, state);
2180
2181                                         if (!stitch_process_data(state, scene, false)) {
2182                                                 stitch_cancel(C, op);
2183                                                 return OPERATOR_CANCELLED;
2184                                         }
2185                                 }
2186                                 break;
2187                         }
2188                         ATTR_FALLTHROUGH;
2189                 case PADENTER:
2190                 case RETKEY:
2191                         if (event->val == KM_PRESS) {
2192                                 if (stitch_process_data(state, scene, true)) {
2193                                         stitch_exit(C, op, 1);
2194                                         return OPERATOR_FINISHED;
2195                                 }
2196                                 else {
2197                                         stitch_cancel(C, op);
2198                                         return OPERATOR_CANCELLED;
2199                                 }
2200                         }
2201                         else {
2202                                 return OPERATOR_PASS_THROUGH;
2203                         }
2204                         /* Increase limit */
2205                 case PADPLUSKEY:
2206                 case WHEELUPMOUSE:
2207                         if (event->val == KM_PRESS && event->alt) {
2208                                 state->limit_dist += 0.01f;
2209                                 if (!stitch_process_data(state, scene, false)) {
2210                                         stitch_cancel(C, op);
2211                                         return OPERATOR_CANCELLED;
2212                                 }
2213                                 break;
2214                         }
2215                         else {
2216                                 return OPERATOR_PASS_THROUGH;
2217                         }
2218                         /* Decrease limit */
2219                 case PADMINUS:
2220                 case WHEELDOWNMOUSE:
2221                         if (event->val == KM_PRESS && event->alt) {
2222                                 state->limit_dist -= 0.01f;
2223                                 state->limit_dist = MAX2(0.01f, state->limit_dist);
2224                                 if (!stitch_process_data(state, scene, false)) {
2225                                         stitch_cancel(C, op);
2226                                         return OPERATOR_CANCELLED;
2227                                 }
2228                                 break;
2229                         }
2230                         else {
2231                                 return OPERATOR_PASS_THROUGH;
2232                         }
2233
2234                         /* Use Limit (Default off) */
2235                 case LKEY:
2236                         if (event->val == KM_PRESS) {
2237                                 state->use_limit = !state->use_limit;
2238                                 if (!stitch_process_data(state, scene, false)) {
2239                                         stitch_cancel(C, op);
2240                                         return OPERATOR_CANCELLED;
2241                                 }
2242                                 break;
2243                         }
2244                         return OPERATOR_RUNNING_MODAL;
2245
2246                 case IKEY:
2247                         if (event->val == KM_PRESS) {
2248                                 state->static_island++;
2249                                 state->static_island %= state->element_map->totalIslands;
2250
2251                                 if (!stitch_process_data(state, scene, false)) {
2252                                         stitch_cancel(C, op);
2253                                         return OPERATOR_CANCELLED;
2254                                 }
2255                                 break;
2256                         }
2257                         return OPERATOR_RUNNING_MODAL;
2258
2259                 case MKEY:
2260                         if (event->val == KM_PRESS) {
2261                                 state->midpoints = !state->midpoints;
2262                                 if (!stitch_process_data(state, scene, false)) {
2263                                         stitch_cancel(C, op);
2264                                         return OPERATOR_CANCELLED;
2265                                 }
2266                         }
2267                         break;
2268
2269                         /* Select geometry */
2270                 case RIGHTMOUSE:
2271                         if (!event->shift) {
2272                                 stitch_cancel(C, op);
2273                                 return OPERATOR_CANCELLED;
2274                         }
2275                         if (event->val == KM_PRESS && !(U.flag & USER_LMOUSESELECT)) {
2276                                 stitch_select(C, scene, event, state);
2277
2278                                 if (!stitch_process_data(state, scene, false)) {
2279                                         stitch_cancel(C, op);
2280                                         return OPERATOR_CANCELLED;
2281                                 }
2282                                 break;
2283                         }
2284                         return OPERATOR_RUNNING_MODAL;
2285
2286                         /* snap islands on/off */
2287                 case SKEY:
2288                         if (event->val == KM_PRESS) {
2289                                 state->snap_islands = !state->snap_islands;
2290                                 if (!stitch_process_data(state, scene, false)) {
2291                                         stitch_cancel(C, op);
2292                                         return OPERATOR_CANCELLED;
2293                                 }
2294                                 break;
2295                         }
2296                         else {
2297                                 return OPERATOR_RUNNING_MODAL;
2298                         }
2299
2300                         /* switch between edge/vertex mode */
2301                 case TABKEY:
2302                         if (event->val == KM_PRESS) {
2303                                 stitch_switch_selection_mode(state);
2304
2305                                 if (!stitch_process_data(state, scene, false)) {
2306                                         stitch_cancel(C, op);
2307                                         return OPERATOR_CANCELLED;
2308                                 }
2309                         }
2310                         break;
2311
2312                 default:
2313                         return OPERATOR_RUNNING_MODAL;
2314         }
2315
2316         /* if updated settings, renew feedback message */
2317         stitch_update_header(state, C);
2318         ED_region_tag_redraw(CTX_wm_region(C));
2319         return OPERATOR_RUNNING_MODAL;
2320 }
2321
2322 void UV_OT_stitch(wmOperatorType *ot)
2323 {
2324         PropertyRNA *prop;
2325
2326         static const EnumPropertyItem stitch_modes[] = {
2327             {STITCH_VERT, "VERTEX", 0, "Vertex", ""},
2328             {STITCH_EDGE, "EDGE", 0, "Edge", ""},
2329             {0, NULL, 0, NULL, NULL}
2330         };
2331
2332         /* identifiers */
2333         ot->name = "Stitch";
2334         ot->description = "Stitch selected UV vertices by proximity";
2335         ot->idname = "UV_OT_stitch";
2336         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2337         
2338         /* api callbacks */
2339         ot->invoke = stitch_invoke;
2340         ot->modal = stitch_modal;
2341         ot->exec = stitch_exec;
2342         ot->cancel = stitch_cancel;
2343         ot->poll = ED_operator_uvedit;
2344
2345         /* properties */
2346         RNA_def_boolean(ot->srna, "use_limit", 0, "Use Limit", "Stitch UVs within a specified limit distance");
2347         RNA_def_boolean(ot->srna, "snap_islands", 1, "Snap Islands",
2348                         "Snap islands together (on edge stitch mode, rotates the islands too)");
2349
2350         RNA_def_float(ot->srna, "limit", 0.01f, 0.0f, FLT_MAX, "Limit",
2351                       "Limit distance in normalized coordinates", 0.0, FLT_MAX);
2352         RNA_def_int(ot->srna, "static_island", 0, 0, INT_MAX, "Static Island",
2353                     "Island that stays in place when stitching islands", 0, INT_MAX);
2354         RNA_def_boolean(ot->srna, "midpoint_snap", 0, "Snap At Midpoint",
2355                         "UVs are stitched at midpoint instead of at static island");
2356         RNA_def_boolean(ot->srna, "clear_seams", 1, "Clear Seams",
2357                         "Clear seams of stitched edges");
2358         RNA_def_enum(ot->srna, "mode", stitch_modes, STITCH_VERT, "Operation Mode",
2359                      "Use vertex or edge stitching");
2360         prop =  RNA_def_enum(ot->srna, "stored_mode", stitch_modes, STITCH_VERT, "Stored Operation Mode",
2361                              "Use vertex or edge stitching");
2362         RNA_def_property_flag(prop, PROP_HIDDEN);
2363         prop = RNA_def_collection_runtime(ot->srna, "selection", &RNA_SelectedUvElement, "Selection", "");
2364         /* Selection should not be editable or viewed in toolbar */
2365         RNA_def_property_flag(prop, PROP_HIDDEN);
2366 }