Blender  V2.93
uvedit_smart_stitch.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19 
24 #include <math.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "MEM_guardedalloc.h"
29 
30 #include "DNA_meshdata_types.h"
31 #include "DNA_object_types.h"
32 #include "DNA_scene_types.h"
33 
34 #include "BLI_ghash.h"
35 #include "BLI_math.h"
36 #include "BLI_math_vector.h"
37 #include "BLI_string.h"
38 #include "BLI_utildefines.h"
39 
40 #include "BLT_translation.h"
41 
42 #include "BKE_context.h"
43 #include "BKE_customdata.h"
44 #include "BKE_editmesh.h"
45 #include "BKE_layer.h"
46 #include "BKE_mesh_mapping.h"
47 
48 #include "DEG_depsgraph.h"
49 
50 #include "UI_interface.h"
51 
52 #include "ED_mesh.h"
53 #include "ED_screen.h"
54 #include "ED_space_api.h"
55 #include "ED_uvedit.h"
56 
57 #include "GPU_batch.h"
58 #include "GPU_state.h"
59 
60 #include "RNA_access.h"
61 #include "RNA_define.h"
62 
63 #include "WM_api.h"
64 #include "WM_types.h"
65 
66 #include "UI_resources.h"
67 #include "UI_view2d.h"
68 
69 #include "uvedit_intern.h"
70 
71 /* ********************** smart stitch operator *********************** */
72 
73 /* object that stores display data for previewing before confirming stitching */
74 typedef struct StitchPreviewer {
75  /* here we'll store the preview triangle indices of the mesh */
76  float *preview_polys;
77  /* uvs per polygon. */
79  /*number of preview polygons */
81  /* preview data. These will be either the previewed vertices or edges
82  * depending on stitch mode settings */
85  /* here we'll store the number of elements to be drawn */
89  /* ...and here we'll store the static island triangles */
90  float *static_tris;
93 
94 struct IslandStitchData;
95 
101 typedef struct IslandStitchData {
102  /* rotation can be used only for edges, for vertices there is no such notion */
103  float rotation;
105  float translation[2];
106  /* Used for rotation, the island will rotate around this point */
107  float medianPoint[2];
111  /* flag to remember if island has been added for preview */
113  /* flag an island to be considered for determining static island */
115  /* if edge rotation is used, flag so that vertex rotation is not used */
118 
119 /* just for averaging UVs */
120 typedef struct UVVertAverage {
121  float uv[2];
124 
125 typedef struct UvEdge {
127  uint uv1;
128  uint uv2;
139  struct UvEdge *next;
141  struct UvEdge *first;
143 
144 /* stitch state object */
145 typedef struct StitchState {
146  float aspect;
147  /* object for editmesh */
149  /* editmesh, cached for use in modal handler */
151 
152  /* element map for getting info about uv connectivity */
154  /* edge container */
156  /* container of first of a group of coincident uvs, these will be operated upon */
158  /* maps uvelements to their first coincident uv */
159  int *map;
160  /* 2D normals per uv to calculate rotation for snapping */
161  float *normals;
162  /* edge storage */
164  /* hash for quick lookup of edges */
166  /* which islands to stop at (to make active) when pressing 'I' */
168 
169  /* count of separate uvs and edges */
172  /* hold selection related information */
175 
176  /* store number of primitives per face so that we can allocate the active island buffer later */
178  /* preview data */
181 
182 /* Stitch state container. */
183 typedef struct StitchStateContainer {
184  /* clear seams of stitched edges after stitch */
186  /* use limit flag */
187  bool use_limit;
188  /* limit to operator, same as original operator */
189  float limit_dist;
190  /* snap uv islands together during stitching */
192  /* stitch at midpoints or at islands */
193  bool midpoints;
194  /* vert or edge mode used for stitching */
195  char mode;
196  /* handle for drawing */
197  void *draw_handle;
198  /* island that stays in place */
200 
201  /* Objects and states are aligned. */
205 
208 
209 typedef struct PreviewPosition {
213 /*
214  * defines for UvElement/UcEdge flags
215  */
216 #define STITCH_SELECTED 1
217 #define STITCH_STITCHABLE 2
218 #define STITCH_PROCESSED 4
219 #define STITCH_BOUNDARY 8
220 #define STITCH_STITCHABLE_CANDIDATE 16
221 
222 #define STITCH_NO_PREVIEW -1
223 
227 };
228 
230 typedef struct UvElementID {
234 
236 typedef struct StitchStateInit {
240 
241 /* constructor */
243 {
244  StitchPreviewer *stitch_preview;
245 
246  stitch_preview = MEM_mallocN(sizeof(StitchPreviewer), "stitch_previewer");
247  stitch_preview->preview_polys = NULL;
248  stitch_preview->preview_stitchable = NULL;
249  stitch_preview->preview_unstitchable = NULL;
250  stitch_preview->uvs_per_polygon = NULL;
251 
252  stitch_preview->preview_uvs = 0;
253  stitch_preview->num_polys = 0;
254  stitch_preview->num_stitchable = 0;
255  stitch_preview->num_unstitchable = 0;
256 
257  stitch_preview->static_tris = NULL;
258 
259  stitch_preview->num_static_tris = 0;
260 
261  return stitch_preview;
262 }
263 
264 /* destructor...yeah this should be C++ :) */
265 static void stitch_preview_delete(StitchPreviewer *stitch_preview)
266 {
267  if (stitch_preview) {
268  if (stitch_preview->preview_polys) {
269  MEM_freeN(stitch_preview->preview_polys);
270  stitch_preview->preview_polys = NULL;
271  }
272  if (stitch_preview->uvs_per_polygon) {
273  MEM_freeN(stitch_preview->uvs_per_polygon);
274  stitch_preview->uvs_per_polygon = NULL;
275  }
276  if (stitch_preview->preview_stitchable) {
277  MEM_freeN(stitch_preview->preview_stitchable);
278  stitch_preview->preview_stitchable = NULL;
279  }
280  if (stitch_preview->preview_unstitchable) {
281  MEM_freeN(stitch_preview->preview_unstitchable);
282  stitch_preview->preview_unstitchable = NULL;
283  }
284  if (stitch_preview->static_tris) {
285  MEM_freeN(stitch_preview->static_tris);
286  stitch_preview->static_tris = NULL;
287  }
288  MEM_freeN(stitch_preview);
289  }
290 }
291 
292 /* This function updates the header of the UV editor when the stitch tool updates its settings */
294 {
295  const char *str = TIP_(
296  "Mode(TAB) %s, "
297  "(S)nap %s, "
298  "(M)idpoints %s, "
299  "(L)imit %.2f (Alt Wheel adjust) %s, "
300  "Switch (I)sland, "
301  "shift select vertices");
302 
303  char msg[UI_MAX_DRAW_STR];
305 
306  if (area) {
307  BLI_snprintf(msg,
308  sizeof(msg),
309  str,
310  ssc->mode == STITCH_VERT ? TIP_("Vertex") : TIP_("Edge"),
313  ssc->limit_dist,
315 
317  }
318 }
319 
320 static int getNumOfIslandUvs(UvElementMap *elementMap, int island)
321 {
322  if (island == elementMap->totalIslands - 1) {
323  return elementMap->totalUVs - elementMap->islandIndices[island];
324  }
325  return elementMap->islandIndices[island + 1] - elementMap->islandIndices[island];
326 }
327 
328 static void stitch_uv_rotate(const float mat[2][2],
329  const float medianPoint[2],
330  float uv[2],
331  float aspect)
332 {
333  float uv_rotation_result[2];
334 
335  uv[1] /= aspect;
336 
337  sub_v2_v2(uv, medianPoint);
338  mul_v2_m2v2(uv_rotation_result, mat, uv);
339  add_v2_v2v2(uv, uv_rotation_result, medianPoint);
340 
341  uv[1] *= aspect;
342 }
343 
344 /* check if two uvelements are stitchable.
345  * This should only operate on -different- separate UvElements */
347  UvElement *element_iter,
350 {
351  BMesh *bm = state->em->bm;
352  float limit;
353 
354  if (element_iter == element) {
355  return 0;
356  }
357 
358  limit = ssc->limit_dist;
359 
360  if (ssc->use_limit) {
361  MLoopUV *luv, *luv_iter;
362  BMLoop *l;
363 
364  l = element->l;
366  l = element_iter->l;
367  luv_iter = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
368 
369  if (fabsf(luv->uv[0] - luv_iter->uv[0]) < limit &&
370  fabsf(luv->uv[1] - luv_iter->uv[1]) < limit) {
371  return 1;
372  }
373  return 0;
374  }
375  return 1;
376 }
377 
379  UvEdge *edge_iter,
382 {
383  BMesh *bm = state->em->bm;
384  float limit;
385 
386  if (edge_iter == edge) {
387  return 0;
388  }
389 
390  limit = ssc->limit_dist;
391 
392  if (ssc->use_limit) {
393  BMLoop *l;
394  MLoopUV *luv_orig1, *luv_iter1;
395  MLoopUV *luv_orig2, *luv_iter2;
396 
397  l = state->uvs[edge->uv1]->l;
398  luv_orig1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
399  l = state->uvs[edge_iter->uv1]->l;
400  luv_iter1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
401 
402  l = state->uvs[edge->uv2]->l;
403  luv_orig2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
404  l = state->uvs[edge_iter->uv2]->l;
405  luv_iter2 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
406 
407  if (fabsf(luv_orig1->uv[0] - luv_iter1->uv[0]) < limit &&
408  fabsf(luv_orig1->uv[1] - luv_iter1->uv[1]) < limit &&
409  fabsf(luv_orig2->uv[0] - luv_iter2->uv[0]) < limit &&
410  fabsf(luv_orig2->uv[1] - luv_iter2->uv[1]) < limit) {
411  return 1;
412  }
413  return 0;
414  }
415  return 1;
416 }
417 
419  UvElement *element_iter,
422 {
423  if ((ssc->snap_islands && element->island == element_iter->island) ||
424  (!ssc->midpoints && element->island == element_iter->island)) {
425  return 0;
426  }
427 
428  return stitch_check_uvs_stitchable(element, element_iter, ssc, state);
429 }
430 
432  UvEdge *edge_iter,
435 {
436  if ((ssc->snap_islands && edge->element->island == edge_iter->element->island) ||
437  (!ssc->midpoints && edge->element->island == edge_iter->element->island)) {
438  return 0;
439  }
440 
441  return stitch_check_edges_stitchable(edge, edge_iter, ssc, state);
442 }
443 
444 /* calculate snapping for islands */
446  PreviewPosition *preview_position,
447  StitchPreviewer *preview,
448  IslandStitchData *island_stitch_data,
449  int final)
450 {
451  BMesh *bm = state->em->bm;
452  int i;
454 
455  for (i = 0; i < state->element_map->totalIslands; i++) {
456  if (island_stitch_data[i].addedForPreview) {
457  int numOfIslandUVs = 0, j;
458  int totelem = island_stitch_data[i].num_rot_elements_neg +
459  island_stitch_data[i].num_rot_elements;
460  float rotation;
461  float rotation_mat[2][2];
462 
463  /* check to avoid divide by 0 */
464  if (island_stitch_data[i].num_rot_elements > 1) {
465  island_stitch_data[i].rotation /= island_stitch_data[i].num_rot_elements;
466  }
467 
468  if (island_stitch_data[i].num_rot_elements_neg > 1) {
469  island_stitch_data[i].rotation_neg /= island_stitch_data[i].num_rot_elements_neg;
470  }
471 
472  if (island_stitch_data[i].numOfElements > 1) {
473  island_stitch_data[i].medianPoint[0] /= island_stitch_data[i].numOfElements;
474  island_stitch_data[i].medianPoint[1] /= island_stitch_data[i].numOfElements;
475 
476  island_stitch_data[i].translation[0] /= island_stitch_data[i].numOfElements;
477  island_stitch_data[i].translation[1] /= island_stitch_data[i].numOfElements;
478  }
479 
480  island_stitch_data[i].medianPoint[1] /= state->aspect;
481  if ((island_stitch_data[i].rotation + island_stitch_data[i].rotation_neg < (float)M_PI_2) ||
482  island_stitch_data[i].num_rot_elements == 0 ||
483  island_stitch_data[i].num_rot_elements_neg == 0) {
484  rotation = (island_stitch_data[i].rotation * island_stitch_data[i].num_rot_elements -
485  island_stitch_data[i].rotation_neg *
486  island_stitch_data[i].num_rot_elements_neg) /
487  totelem;
488  }
489  else {
490  rotation = (island_stitch_data[i].rotation * island_stitch_data[i].num_rot_elements +
491  (2.0f * (float)M_PI - island_stitch_data[i].rotation_neg) *
492  island_stitch_data[i].num_rot_elements_neg) /
493  totelem;
494  }
495 
496  angle_to_mat2(rotation_mat, rotation);
497  numOfIslandUVs = getNumOfIslandUvs(state->element_map, i);
498  element = &state->element_map->buf[state->element_map->islandIndices[i]];
499  for (j = 0; j < numOfIslandUVs; j++, element++) {
500  /* stitchable uvs have already been processed, don't process */
501  if (!(element->flag & STITCH_PROCESSED)) {
502  MLoopUV *luv;
503  BMLoop *l;
504 
505  l = element->l;
507 
508  if (final) {
509 
511  rotation_mat, island_stitch_data[i].medianPoint, luv->uv, state->aspect);
512 
513  add_v2_v2(luv->uv, island_stitch_data[i].translation);
514  }
515 
516  else {
517 
518  int face_preview_pos =
519  preview_position[BM_elem_index_get(element->l->f)].data_position;
520 
521  stitch_uv_rotate(rotation_mat,
522  island_stitch_data[i].medianPoint,
523  preview->preview_polys + face_preview_pos +
524  2 * element->loop_of_poly_index,
525  state->aspect);
526 
527  add_v2_v2(preview->preview_polys + face_preview_pos + 2 * element->loop_of_poly_index,
528  island_stitch_data[i].translation);
529  }
530  }
531  /* cleanup */
532  element->flag &= STITCH_SELECTED;
533  }
534  }
535  }
536 }
537 
541  UVVertAverage *uv_average,
542  const uint *uvfinal_map,
543  IslandStitchData *island_stitch_data)
544 {
545  BMesh *bm = state->em->bm;
546  UvElement *element1, *element2;
547  float uv1[2], uv2[2];
548  float edgecos, edgesin;
549  int index1, index2;
550  float rotation;
551  MLoopUV *luv1, *luv2;
552 
553  element1 = state->uvs[edge->uv1];
554  element2 = state->uvs[edge->uv2];
555 
556  luv1 = CustomData_bmesh_get(&bm->ldata, element1->l->head.data, CD_MLOOPUV);
557  luv2 = CustomData_bmesh_get(&bm->ldata, element2->l->head.data, CD_MLOOPUV);
558 
559  if (ssc->mode == STITCH_VERT) {
560  index1 = uvfinal_map[element1 - state->element_map->buf];
561  index2 = uvfinal_map[element2 - state->element_map->buf];
562  }
563  else {
564  index1 = edge->uv1;
565  index2 = edge->uv2;
566  }
567  /* the idea here is to take the directions of the edges and find the rotation between
568  * final and initial direction. This, using inner and outer vector products,
569  * gives the angle. Directions are differences so... */
570  uv1[0] = luv2->uv[0] - luv1->uv[0];
571  uv1[1] = luv2->uv[1] - luv1->uv[1];
572 
573  uv1[1] /= state->aspect;
574 
575  uv2[0] = uv_average[index2].uv[0] - uv_average[index1].uv[0];
576  uv2[1] = uv_average[index2].uv[1] - uv_average[index1].uv[1];
577 
578  uv2[1] /= state->aspect;
579 
580  normalize_v2(uv1);
581  normalize_v2(uv2);
582 
583  edgecos = dot_v2v2(uv1, uv2);
584  edgesin = cross_v2v2(uv1, uv2);
585  rotation = acosf(max_ff(-1.0f, min_ff(1.0f, edgecos)));
586 
587  if (edgesin > 0.0f) {
588  island_stitch_data[element1->island].num_rot_elements++;
589  island_stitch_data[element1->island].rotation += rotation;
590  }
591  else {
592  island_stitch_data[element1->island].num_rot_elements_neg++;
593  island_stitch_data[element1->island].rotation_neg += rotation;
594  }
595 }
596 
600  IslandStitchData *island_stitch_data)
601 {
602  float edgecos = 1.0f, edgesin = 0.0f;
603  int index;
604  UvElement *element_iter;
605  float rotation = 0, rotation_neg = 0;
606  int rot_elem = 0, rot_elem_neg = 0;
607  BMLoop *l;
608 
609  if (element->island == ssc->static_island && !ssc->midpoints) {
610  return;
611  }
612 
613  l = element->l;
614 
615  index = BM_elem_index_get(l->v);
616 
617  element_iter = state->element_map->vert[index];
618 
619  for (; element_iter; element_iter = element_iter->next) {
620  if (element_iter->separate &&
621  stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) {
622  int index_tmp1, index_tmp2;
623  float normal[2];
624 
625  /* only calculate rotation against static island uv verts */
626  if (!ssc->midpoints && element_iter->island != ssc->static_island) {
627  continue;
628  }
629 
630  index_tmp1 = element_iter - state->element_map->buf;
631  index_tmp1 = state->map[index_tmp1];
632  index_tmp2 = element - state->element_map->buf;
633  index_tmp2 = state->map[index_tmp2];
634 
635  negate_v2_v2(normal, state->normals + index_tmp2 * 2);
636  edgecos = dot_v2v2(normal, state->normals + index_tmp1 * 2);
637  edgesin = cross_v2v2(normal, state->normals + index_tmp1 * 2);
638  if (edgesin > 0.0f) {
639  rotation += acosf(max_ff(-1.0f, min_ff(1.0f, edgecos)));
640  rot_elem++;
641  }
642  else {
643  rotation_neg += acosf(max_ff(-1.0f, min_ff(1.0f, edgecos)));
644  rot_elem_neg++;
645  }
646  }
647  }
648 
649  if (ssc->midpoints) {
650  rotation /= 2.0f;
651  rotation_neg /= 2.0f;
652  }
653  island_stitch_data[element->island].num_rot_elements += rot_elem;
654  island_stitch_data[element->island].rotation += rotation;
655  island_stitch_data[element->island].num_rot_elements_neg += rot_elem_neg;
656  island_stitch_data[element->island].rotation_neg += rotation_neg;
657 }
658 
660 {
661  if (state) {
662  if (state->island_is_stitchable) {
663  MEM_freeN(state->island_is_stitchable);
664  }
665  if (state->element_map) {
666  BM_uv_element_map_free(state->element_map);
667  }
668  if (state->uvs) {
669  MEM_freeN(state->uvs);
670  }
671  if (state->selection_stack) {
672  MEM_freeN(state->selection_stack);
673  }
674  if (state->tris_per_island) {
675  MEM_freeN(state->tris_per_island);
676  }
677  if (state->map) {
678  MEM_freeN(state->map);
679  }
680  if (state->normals) {
681  MEM_freeN(state->normals);
682  }
683  if (state->edges) {
684  MEM_freeN(state->edges);
685  }
686  if (state->stitch_preview) {
687  stitch_preview_delete(state->stitch_preview);
688  }
689  if (state->edge_hash) {
690  BLI_ghash_free(state->edge_hash, NULL, NULL);
691  }
692  MEM_freeN(state);
693  }
694 }
695 
697 {
698  if (ssc) {
699  for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
700  state_delete(ssc->states[ob_index]);
701  }
702  MEM_freeN(ssc->states);
703  MEM_freeN(ssc->objects);
704  MEM_freeN(ssc);
705  }
706 }
707 
709 {
710  UvEdge *edges = state->edges;
711  const int *map = state->map;
712  UvElementMap *element_map = state->element_map;
713  UvElement *first_element = element_map->buf;
714  int i;
715 
716  for (i = 0; i < state->total_separate_edges; i++) {
717  UvEdge *edge = edges + i;
718 
719  if (edge->first) {
720  continue;
721  }
722 
723  /* only boundary edges can be stitched. Yes. Sorry about that :p */
724  if (edge->flag & STITCH_BOUNDARY) {
725  UvElement *element1 = state->uvs[edge->uv1];
726  UvElement *element2 = state->uvs[edge->uv2];
727 
728  /* Now iterate through all faces and try to find edges sharing the same vertices */
729  UvElement *iter1 = element_map->vert[BM_elem_index_get(element1->l->v)];
730  UvEdge *last_set = edge;
731  int elemindex2 = BM_elem_index_get(element2->l->v);
732 
733  edge->first = edge;
734 
735  for (; iter1; iter1 = iter1->next) {
736  UvElement *iter2 = NULL;
737 
738  /* check to see if other vertex of edge belongs to same vertex as */
739  if (BM_elem_index_get(iter1->l->next->v) == elemindex2) {
740  iter2 = BM_uv_element_get(element_map, iter1->l->f, iter1->l->next);
741  }
742  else if (BM_elem_index_get(iter1->l->prev->v) == elemindex2) {
743  iter2 = BM_uv_element_get(element_map, iter1->l->f, iter1->l->prev);
744  }
745 
746  if (iter2) {
747  int index1 = map[iter1 - first_element];
748  int index2 = map[iter2 - first_element];
749  UvEdge edgetmp;
750  UvEdge *edge2, *eiter;
751  bool valid = true;
752 
753  /* make sure the indices are well behaved */
754  if (index1 > index2) {
755  SWAP(int, index1, index2);
756  }
757 
758  edgetmp.uv1 = index1;
759  edgetmp.uv2 = index2;
760 
761  /* get the edge from the hash */
762  edge2 = BLI_ghash_lookup(edge_hash, &edgetmp);
763 
764  /* more iteration to make sure non-manifold case is handled nicely */
765  for (eiter = edge; eiter; eiter = eiter->next) {
766  if (edge2 == eiter) {
767  valid = false;
768  break;
769  }
770  }
771 
772  if (valid) {
773  /* here I am taking care of non manifold case, assuming more than two matching edges.
774  * I am not too sure we want this though */
775  last_set->next = edge2;
776  last_set = edge2;
777  /* set first, similarly to uv elements.
778  * Now we can iterate among common edges easily */
779  edge2->first = edge;
780  }
781  }
782  }
783  }
784  else {
785  /* so stitchability code works */
786  edge->first = edge;
787  }
788  }
789 }
790 
791 /* checks for remote uvs that may be stitched with a certain uv, flags them if stitchable. */
795  IslandStitchData *island_stitch_data)
796 {
797  int vert_index;
798  UvElement *element_iter;
799  BMLoop *l;
800 
801  l = element->l;
802 
803  vert_index = BM_elem_index_get(l->v);
804  element_iter = state->element_map->vert[vert_index];
805 
806  for (; element_iter; element_iter = element_iter->next) {
807  if (element_iter->separate) {
808  if (stitch_check_uvs_stitchable(element, element_iter, ssc, state)) {
809  island_stitch_data[element_iter->island].stitchableCandidate = 1;
810  island_stitch_data[element->island].stitchableCandidate = 1;
812  }
813  }
814  }
815 }
816 
820  IslandStitchData *island_stitch_data)
821 {
822  UvEdge *edge_iter = edge->first;
823 
824  for (; edge_iter; edge_iter = edge_iter->next) {
825  if (stitch_check_edges_stitchable(edge, edge_iter, ssc, state)) {
826  island_stitch_data[edge_iter->element->island].stitchableCandidate = 1;
827  island_stitch_data[edge->element->island].stitchableCandidate = 1;
829  }
830  }
831 }
832 
833 /* set preview buffer position of UV face in editface->tmp.l */
835  StitchPreviewer *preview,
836  PreviewPosition *preview_position)
837 {
838  int index = BM_elem_index_get(efa);
839 
840  if (preview_position[index].data_position == STITCH_NO_PREVIEW) {
841  preview_position[index].data_position = preview->preview_uvs * 2;
842  preview_position[index].polycount_position = preview->num_polys++;
843  preview->preview_uvs += efa->len;
844  }
845 }
846 
847 /* setup face preview for all coincident uvs and their faces */
851  IslandStitchData *island_stitch_data,
852  PreviewPosition *preview_position)
853 {
854  StitchPreviewer *preview = state->stitch_preview;
855 
856  /* static island does not change so returning immediately */
857  if (ssc->snap_islands && !ssc->midpoints && ssc->static_island == element->island) {
858  return;
859  }
860 
861  if (ssc->snap_islands) {
862  island_stitch_data[element->island].addedForPreview = 1;
863  }
864 
865  do {
866  stitch_set_face_preview_buffer_position(element->l->f, preview, preview_position);
867  element = element->next;
868  } while (element && !element->separate);
869 }
870 
871 /* checks if uvs are indeed stitchable and registers so that they can be shown in preview */
875  IslandStitchData *island_stitch_data,
876  PreviewPosition *preview_position)
877 {
878  StitchPreviewer *preview = state->stitch_preview;
879 
880  /* If not the active object, then it's unstitchable */
881  if (ssc->states[ssc->active_object_index] != state) {
882  preview->num_unstitchable++;
883  return;
884  }
885 
886  UvElement *element_iter;
887  int vert_index;
888  BMLoop *l;
889 
890  l = element->l;
891 
892  vert_index = BM_elem_index_get(l->v);
893 
894  element_iter = state->element_map->vert[vert_index];
895 
896  for (; element_iter; element_iter = element_iter->next) {
897  if (element_iter->separate) {
898  if (element_iter == element) {
899  continue;
900  }
901  if (stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) {
902  if ((element_iter->island == ssc->static_island) ||
903  (element->island == ssc->static_island)) {
904  element->flag |= STITCH_STITCHABLE;
905  preview->num_stitchable++;
907  element, ssc, state, island_stitch_data, preview_position);
908  return;
909  }
910  }
911  }
912  }
913 
914  /* this can happen if the uvs to be stitched are not on a stitchable island */
915  if (!(element->flag & STITCH_STITCHABLE)) {
916  preview->num_unstitchable++;
917  }
918 }
919 
923  IslandStitchData *island_stitch_data,
924  PreviewPosition *preview_position)
925 {
926  StitchPreviewer *preview = state->stitch_preview;
927 
928  /* If not the active object, then it's unstitchable */
929  if (ssc->states[ssc->active_object_index] != state) {
930  preview->num_unstitchable++;
931  return;
932  }
933 
934  UvEdge *edge_iter = edge->first;
935 
936  for (; edge_iter; edge_iter = edge_iter->next) {
937  if (edge_iter == edge) {
938  continue;
939  }
940  if (stitch_check_edges_state_stitchable(edge, edge_iter, ssc, state)) {
941  if ((edge_iter->element->island == ssc->static_island) ||
942  (edge->element->island == ssc->static_island)) {
943  edge->flag |= STITCH_STITCHABLE;
944  preview->num_stitchable++;
946  state->uvs[edge->uv1], ssc, state, island_stitch_data, preview_position);
948  state->uvs[edge->uv2], ssc, state, island_stitch_data, preview_position);
949  return;
950  }
951  }
952  }
953 
954  /* this can happen if the uvs to be stitched are not on a stitchable island */
955  if (!(edge->flag & STITCH_STITCHABLE)) {
956  preview->num_unstitchable++;
957  }
958 }
959 
962  int index,
963  PreviewPosition *preview_position,
964  UVVertAverage *final_position,
967  const bool final)
968 {
969  BMesh *bm = state->em->bm;
970  StitchPreviewer *preview = state->stitch_preview;
971 
972  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
973 
974  if (element->flag & STITCH_STITCHABLE) {
975  UvElement *element_iter = element;
976  /* propagate to coincident uvs */
977  do {
978  BMLoop *l;
979  MLoopUV *luv;
980 
981  l = element_iter->l;
983 
984  element_iter->flag |= STITCH_PROCESSED;
985  /* either flush to preview or to the MTFace, if final */
986  if (final) {
987  copy_v2_v2(luv->uv, final_position[index].uv);
988 
989  uvedit_uv_select_enable(scene, state->em, l, false, cd_loop_uv_offset);
990  }
991  else {
992  int face_preview_pos =
993  preview_position[BM_elem_index_get(element_iter->l->f)].data_position;
994  if (face_preview_pos != STITCH_NO_PREVIEW) {
995  copy_v2_v2(preview->preview_polys + face_preview_pos +
996  2 * element_iter->loop_of_poly_index,
997  final_position[index].uv);
998  }
999  }
1000 
1001  /* end of calculations, keep only the selection flag */
1002  if ((!ssc->snap_islands) ||
1003  ((!ssc->midpoints) && (element_iter->island == ssc->static_island))) {
1004  element_iter->flag &= STITCH_SELECTED;
1005  }
1006 
1007  element_iter = element_iter->next;
1008  } while (element_iter && !element_iter->separate);
1009  }
1010 }
1011 
1012 /* main processing function. It calculates preview and final positions. */
1014  StitchState *state,
1015  Scene *scene,
1016  int final)
1017 {
1018  int i;
1019  StitchPreviewer *preview;
1020  IslandStitchData *island_stitch_data = NULL;
1021  int previous_island = ssc->static_island;
1022  BMesh *bm = state->em->bm;
1023  BMFace *efa;
1024  BMIter iter;
1025  UVVertAverage *final_position = NULL;
1026  bool is_active_state = (state == ssc->states[ssc->active_object_index]);
1027 
1028  char stitch_midpoints = ssc->midpoints;
1029  /* used to map uv indices to uvaverage indices for selection */
1030  uint *uvfinal_map = NULL;
1031  /* per face preview position in preview buffer */
1032  PreviewPosition *preview_position = NULL;
1033 
1034  /* cleanup previous preview */
1035  stitch_preview_delete(state->stitch_preview);
1036  preview = state->stitch_preview = stitch_preview_init();
1037  if (preview == NULL) {
1038  return 0;
1039  }
1040 
1041  preview_position = MEM_mallocN(bm->totface * sizeof(*preview_position),
1042  "stitch_face_preview_position");
1043  /* each face holds its position in the preview buffer in tmp. -1 is uninitialized */
1044  for (i = 0; i < bm->totface; i++) {
1045  preview_position[i].data_position = STITCH_NO_PREVIEW;
1046  }
1047 
1048  island_stitch_data = MEM_callocN(sizeof(*island_stitch_data) * state->element_map->totalIslands,
1049  "stitch_island_data");
1050  if (!island_stitch_data) {
1051  return 0;
1052  }
1053 
1054  /* store indices to editVerts and Faces. May be unneeded but ensuring anyway */
1056 
1057  /****************************************
1058  * First determine stitchability of uvs *
1059  ****************************************/
1060 
1061  for (i = 0; i < state->selection_size; i++) {
1062  if (ssc->mode == STITCH_VERT) {
1063  UvElement *element = (UvElement *)state->selection_stack[i];
1064  determine_uv_stitchability(element, ssc, state, island_stitch_data);
1065  }
1066  else {
1067  UvEdge *edge = (UvEdge *)state->selection_stack[i];
1068  determine_uv_edge_stitchability(edge, ssc, state, island_stitch_data);
1069  }
1070  }
1071 
1072  /* remember stitchable candidates as places the 'I' button */
1073  /* will stop at. */
1074  for (int island_idx = 0; island_idx < state->element_map->totalIslands; island_idx++) {
1075  state->island_is_stitchable[island_idx] = island_stitch_data[island_idx].stitchableCandidate ?
1076  true :
1077  false;
1078  }
1079 
1080  if (is_active_state) {
1081  /* set static island to one that is added for preview */
1082  ssc->static_island %= state->element_map->totalIslands;
1083  while (!(island_stitch_data[ssc->static_island].stitchableCandidate)) {
1084  ssc->static_island++;
1085  ssc->static_island %= state->element_map->totalIslands;
1086  /* this is entirely possible if for example limit stitching
1087  * with no stitchable verts or no selection */
1088  if (ssc->static_island == previous_island) {
1089  break;
1090  }
1091  }
1092  }
1093 
1094  for (i = 0; i < state->selection_size; i++) {
1095  if (ssc->mode == STITCH_VERT) {
1096  UvElement *element = (UvElement *)state->selection_stack[i];
1100  element, ssc, state, island_stitch_data, preview_position);
1101  }
1102  else {
1103  /* add to preview for unstitchable */
1104  preview->num_unstitchable++;
1105  }
1106  }
1107  else {
1108  UvEdge *edge = (UvEdge *)state->selection_stack[i];
1109  if (edge->flag & STITCH_STITCHABLE_CANDIDATE) {
1111  stitch_validate_edge_stitchability(edge, ssc, state, island_stitch_data, preview_position);
1112  }
1113  else {
1114  preview->num_unstitchable++;
1115  }
1116  }
1117  }
1118 
1119  /*********************************************************************
1120  * Setup the stitchable & unstitchable preview buffers and fill *
1121  * them with the appropriate data *
1122  *********************************************************************/
1123  if (!final) {
1124  BMLoop *l;
1125  MLoopUV *luv;
1126  int stitchBufferIndex = 0, unstitchBufferIndex = 0;
1127  int preview_size = (ssc->mode == STITCH_VERT) ? 2 : 4;
1128  /* initialize the preview buffers */
1129  preview->preview_stitchable = (float *)MEM_mallocN(
1130  preview->num_stitchable * sizeof(float) * preview_size, "stitch_preview_stitchable_data");
1131  preview->preview_unstitchable = (float *)MEM_mallocN(preview->num_unstitchable *
1132  sizeof(float) * preview_size,
1133  "stitch_preview_unstitchable_data");
1134 
1135  /* will cause cancel and freeing of all data structures so OK */
1136  if (!preview->preview_stitchable || !preview->preview_unstitchable) {
1137  return 0;
1138  }
1139 
1140  /* fill the appropriate preview buffers */
1141  if (ssc->mode == STITCH_VERT) {
1142  for (i = 0; i < state->total_separate_uvs; i++) {
1143  UvElement *element = (UvElement *)state->uvs[i];
1144  if (element->flag & STITCH_STITCHABLE) {
1145  l = element->l;
1147 
1148  copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 2], luv->uv);
1149 
1150  stitchBufferIndex++;
1151  }
1152  else if (element->flag & STITCH_SELECTED) {
1153  l = element->l;
1155 
1156  copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 2], luv->uv);
1157  unstitchBufferIndex++;
1158  }
1159  }
1160  }
1161  else {
1162  for (i = 0; i < state->total_separate_edges; i++) {
1163  UvEdge *edge = state->edges + i;
1164  UvElement *element1 = state->uvs[edge->uv1];
1165  UvElement *element2 = state->uvs[edge->uv2];
1166 
1167  if (edge->flag & STITCH_STITCHABLE) {
1168  l = element1->l;
1170  copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 4], luv->uv);
1171 
1172  l = element2->l;
1174  copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 4 + 2], luv->uv);
1175 
1176  stitchBufferIndex++;
1177  BLI_assert(stitchBufferIndex <= preview->num_stitchable);
1178  }
1179  else if (edge->flag & STITCH_SELECTED) {
1180  l = element1->l;
1182  copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 4], luv->uv);
1183 
1184  l = element2->l;
1186  copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 4 + 2], luv->uv);
1187 
1188  unstitchBufferIndex++;
1189  BLI_assert(unstitchBufferIndex <= preview->num_unstitchable);
1190  }
1191  }
1192  }
1193  }
1194 
1195  if (ssc->states[ssc->active_object_index] != state) {
1196  /* This is not the active object/state, exit here */
1197  MEM_freeN(island_stitch_data);
1198  MEM_freeN(preview_position);
1199  return 1;
1200  }
1201 
1202  /****************************************
1203  * Setup preview for stitchable islands *
1204  ****************************************/
1205  if (ssc->snap_islands) {
1206  for (i = 0; i < state->element_map->totalIslands; i++) {
1207  if (island_stitch_data[i].addedForPreview) {
1208  int numOfIslandUVs = 0, j;
1209  UvElement *element;
1210  numOfIslandUVs = getNumOfIslandUvs(state->element_map, i);
1211  element = &state->element_map->buf[state->element_map->islandIndices[i]];
1212  for (j = 0; j < numOfIslandUVs; j++, element++) {
1213  stitch_set_face_preview_buffer_position(element->l->f, preview, preview_position);
1214  }
1215  }
1216  }
1217  }
1218 
1219  /*********************************************************************
1220  * Setup the remaining preview buffers and fill them with the *
1221  * appropriate data *
1222  *********************************************************************/
1223  if (!final) {
1224  BMIter liter;
1225  BMLoop *l;
1226  MLoopUV *luv;
1227  uint buffer_index = 0;
1228 
1229  /* initialize the preview buffers */
1230  preview->preview_polys = MEM_mallocN(sizeof(float[2]) * preview->preview_uvs,
1231  "tri_uv_stitch_prev");
1232  preview->uvs_per_polygon = MEM_mallocN(sizeof(*preview->uvs_per_polygon) * preview->num_polys,
1233  "tri_uv_stitch_prev");
1234 
1235  preview->static_tris = MEM_mallocN(
1236  (sizeof(float[6]) * state->tris_per_island[ssc->static_island]),
1237  "static_island_preview_tris");
1238 
1239  preview->num_static_tris = state->tris_per_island[ssc->static_island];
1240  /* will cause cancel and freeing of all data structures so OK */
1241  if (!preview->preview_polys) {
1242  return 0;
1243  }
1244 
1245  /* copy data from MLoopUVs to the preview display buffers */
1246  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
1247  /* just to test if face was added for processing.
1248  * uvs of unselected vertices will return NULL */
1249  UvElement *element = BM_uv_element_get(state->element_map, efa, BM_FACE_FIRST_LOOP(efa));
1250 
1251  if (element) {
1252  int numoftris = efa->len - 2;
1253  int index = BM_elem_index_get(efa);
1254  int face_preview_pos = preview_position[index].data_position;
1255  if (face_preview_pos != STITCH_NO_PREVIEW) {
1256  preview->uvs_per_polygon[preview_position[index].polycount_position] = efa->len;
1257  BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
1259  copy_v2_v2(preview->preview_polys + face_preview_pos + i * 2, luv->uv);
1260  }
1261  }
1262 
1263  /* if this is the static_island on the active object */
1264  if (element->island == ssc->static_island) {
1265  BMLoop *fl = BM_FACE_FIRST_LOOP(efa);
1267 
1268  BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
1269  if (i < numoftris) {
1270  /* using next since the first uv is already accounted for */
1271  BMLoop *lnext = l->next;
1272  MLoopUV *luvnext = CustomData_bmesh_get(
1273  &bm->ldata, lnext->next->head.data, CD_MLOOPUV);
1274  luv = CustomData_bmesh_get(&bm->ldata, lnext->head.data, CD_MLOOPUV);
1275 
1276  memcpy(preview->static_tris + buffer_index, fuv->uv, sizeof(float[2]));
1277  memcpy(preview->static_tris + buffer_index + 2, luv->uv, sizeof(float[2]));
1278  memcpy(preview->static_tris + buffer_index + 4, luvnext->uv, sizeof(float[2]));
1279  buffer_index += 6;
1280  }
1281  else {
1282  break;
1283  }
1284  }
1285  }
1286  }
1287  }
1288  }
1289 
1290  /******************************************************
1291  * Here we calculate the final coordinates of the uvs *
1292  ******************************************************/
1293 
1294  if (ssc->mode == STITCH_VERT) {
1295  final_position = MEM_callocN(state->selection_size * sizeof(*final_position),
1296  "stitch_uv_average");
1297  uvfinal_map = MEM_mallocN(state->element_map->totalUVs * sizeof(*uvfinal_map),
1298  "stitch_uv_final_map");
1299  }
1300  else {
1301  final_position = MEM_callocN(state->total_separate_uvs * sizeof(*final_position),
1302  "stitch_uv_average");
1303  }
1304 
1305  /* first pass, calculate final position for stitchable uvs of the static island */
1306  for (i = 0; i < state->selection_size; i++) {
1307  if (ssc->mode == STITCH_VERT) {
1308  UvElement *element = state->selection_stack[i];
1309 
1310  if (element->flag & STITCH_STITCHABLE) {
1311  BMLoop *l;
1312  MLoopUV *luv;
1313  UvElement *element_iter;
1314 
1315  l = element->l;
1317 
1318  uvfinal_map[element - state->element_map->buf] = i;
1319 
1320  copy_v2_v2(final_position[i].uv, luv->uv);
1321  final_position[i].count = 1;
1322 
1323  if (ssc->snap_islands && element->island == ssc->static_island && !stitch_midpoints) {
1324  continue;
1325  }
1326 
1327  element_iter = state->element_map->vert[BM_elem_index_get(l->v)];
1328 
1329  for (; element_iter; element_iter = element_iter->next) {
1330  if (element_iter->separate) {
1331  if (stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) {
1332  l = element_iter->l;
1334  if (stitch_midpoints) {
1335  add_v2_v2(final_position[i].uv, luv->uv);
1336  final_position[i].count++;
1337  }
1338  else if (element_iter->island == ssc->static_island) {
1339  /* if multiple uvs on the static island exist,
1340  * last checked remains. to disambiguate we need to limit or use
1341  * edge stitch */
1342  copy_v2_v2(final_position[i].uv, luv->uv);
1343  }
1344  }
1345  }
1346  }
1347  }
1348  if (stitch_midpoints) {
1349  final_position[i].uv[0] /= final_position[i].count;
1350  final_position[i].uv[1] /= final_position[i].count;
1351  }
1352  }
1353  else {
1354  UvEdge *edge = state->selection_stack[i];
1355 
1356  if (edge->flag & STITCH_STITCHABLE) {
1357  MLoopUV *luv2, *luv1;
1358  BMLoop *l;
1359  UvEdge *edge_iter;
1360 
1361  l = state->uvs[edge->uv1]->l;
1363  l = state->uvs[edge->uv2]->l;
1365 
1366  copy_v2_v2(final_position[edge->uv1].uv, luv1->uv);
1367  copy_v2_v2(final_position[edge->uv2].uv, luv2->uv);
1368  final_position[edge->uv1].count = 1;
1369  final_position[edge->uv2].count = 1;
1370 
1371  state->uvs[edge->uv1]->flag |= STITCH_STITCHABLE;
1372  state->uvs[edge->uv2]->flag |= STITCH_STITCHABLE;
1373 
1374  if (ssc->snap_islands && edge->element->island == ssc->static_island &&
1375  !stitch_midpoints) {
1376  continue;
1377  }
1378 
1379  for (edge_iter = edge->first; edge_iter; edge_iter = edge_iter->next) {
1380  if (stitch_check_edges_state_stitchable(edge, edge_iter, ssc, state)) {
1381  l = state->uvs[edge_iter->uv1]->l;
1383  l = state->uvs[edge_iter->uv2]->l;
1385 
1386  if (stitch_midpoints) {
1387  add_v2_v2(final_position[edge->uv1].uv, luv1->uv);
1388  final_position[edge->uv1].count++;
1389  add_v2_v2(final_position[edge->uv2].uv, luv2->uv);
1390  final_position[edge->uv2].count++;
1391  }
1392  else if (edge_iter->element->island == ssc->static_island) {
1393  copy_v2_v2(final_position[edge->uv1].uv, luv1->uv);
1394  copy_v2_v2(final_position[edge->uv2].uv, luv2->uv);
1395  }
1396  }
1397  }
1398  }
1399  }
1400  }
1401 
1402  /* take mean position here.
1403  * For edge case, this can't be done inside the loop for shared uvverts */
1404  if (ssc->mode == STITCH_EDGE && stitch_midpoints) {
1405  for (i = 0; i < state->total_separate_uvs; i++) {
1406  final_position[i].uv[0] /= final_position[i].count;
1407  final_position[i].uv[1] /= final_position[i].count;
1408  }
1409  }
1410 
1411  /* second pass, calculate island rotation and translation before modifying any uvs */
1412  if (ssc->snap_islands) {
1413  if (ssc->mode == STITCH_VERT) {
1414  for (i = 0; i < state->selection_size; i++) {
1415  UvElement *element = state->selection_stack[i];
1416 
1417  if (element->flag & STITCH_STITCHABLE) {
1418  BMLoop *l;
1419  MLoopUV *luv;
1420 
1421  l = element->l;
1423 
1424  /* accumulate each islands' translation from stitchable elements.
1425  * It is important to do here because in final pass MTFaces
1426  * get modified and result is zero. */
1427  island_stitch_data[element->island].translation[0] += final_position[i].uv[0] -
1428  luv->uv[0];
1429  island_stitch_data[element->island].translation[1] += final_position[i].uv[1] -
1430  luv->uv[1];
1431  island_stitch_data[element->island].medianPoint[0] += luv->uv[0];
1432  island_stitch_data[element->island].medianPoint[1] += luv->uv[1];
1433  island_stitch_data[element->island].numOfElements++;
1434  }
1435  }
1436 
1437  /* only calculate rotation when an edge has been fully selected */
1438  for (i = 0; i < state->total_separate_edges; i++) {
1439  UvEdge *edge = state->edges + i;
1440  if ((edge->flag & STITCH_BOUNDARY) && (state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) &&
1441  (state->uvs[edge->uv2]->flag & STITCH_STITCHABLE)) {
1443  edge, ssc, state, final_position, uvfinal_map, island_stitch_data);
1444  island_stitch_data[state->uvs[edge->uv1]->island].use_edge_rotation = true;
1445  }
1446  }
1447 
1448  /* clear seams of stitched edges */
1449  if (final && ssc->clear_seams) {
1450  for (i = 0; i < state->total_separate_edges; i++) {
1451  UvEdge *edge = state->edges + i;
1452  if ((state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) &&
1453  (state->uvs[edge->uv2]->flag & STITCH_STITCHABLE)) {
1455  }
1456  }
1457  }
1458 
1459  for (i = 0; i < state->selection_size; i++) {
1460  UvElement *element = state->selection_stack[i];
1461  if (!island_stitch_data[element->island].use_edge_rotation) {
1462  if (element->flag & STITCH_STITCHABLE) {
1463  stitch_island_calculate_vert_rotation(element, ssc, state, island_stitch_data);
1464  }
1465  }
1466  }
1467  }
1468  else {
1469  for (i = 0; i < state->total_separate_uvs; i++) {
1470  UvElement *element = state->uvs[i];
1471 
1472  if (element->flag & STITCH_STITCHABLE) {
1473  BMLoop *l;
1474  MLoopUV *luv;
1475 
1476  l = element->l;
1478 
1479  /* accumulate each islands' translation from stitchable elements.
1480  * it is important to do here because in final pass MTFaces
1481  * get modified and result is zero. */
1482  island_stitch_data[element->island].translation[0] += final_position[i].uv[0] -
1483  luv->uv[0];
1484  island_stitch_data[element->island].translation[1] += final_position[i].uv[1] -
1485  luv->uv[1];
1486  island_stitch_data[element->island].medianPoint[0] += luv->uv[0];
1487  island_stitch_data[element->island].medianPoint[1] += luv->uv[1];
1488  island_stitch_data[element->island].numOfElements++;
1489  }
1490  }
1491 
1492  for (i = 0; i < state->selection_size; i++) {
1493  UvEdge *edge = state->selection_stack[i];
1494 
1495  if (edge->flag & STITCH_STITCHABLE) {
1497  edge, ssc, state, final_position, NULL, island_stitch_data);
1498  island_stitch_data[state->uvs[edge->uv1]->island].use_edge_rotation = true;
1499  }
1500  }
1501 
1502  /* clear seams of stitched edges */
1503  if (final && ssc->clear_seams) {
1504  for (i = 0; i < state->selection_size; i++) {
1505  UvEdge *edge = state->selection_stack[i];
1506  if (edge->flag & STITCH_STITCHABLE) {
1508  }
1509  }
1510  }
1511  }
1512  }
1513 
1514  /* third pass, propagate changes to coincident uvs */
1515  for (i = 0; i < state->selection_size; i++) {
1516  if (ssc->mode == STITCH_VERT) {
1517  UvElement *element = state->selection_stack[i];
1518 
1520  scene, element, i, preview_position, final_position, ssc, state, final);
1521  }
1522  else {
1523  UvEdge *edge = state->selection_stack[i];
1524 
1526  state->uvs[edge->uv1],
1527  edge->uv1,
1528  preview_position,
1529  final_position,
1530  ssc,
1531  state,
1532  final);
1534  state->uvs[edge->uv2],
1535  edge->uv2,
1536  preview_position,
1537  final_position,
1538  ssc,
1539  state,
1540  final);
1541 
1542  edge->flag &= (STITCH_SELECTED | STITCH_BOUNDARY);
1543  }
1544  }
1545 
1546  /* final pass, calculate Island translation/rotation if needed */
1547  if (ssc->snap_islands) {
1548  stitch_calculate_island_snapping(state, preview_position, preview, island_stitch_data, final);
1549  }
1550 
1551  MEM_freeN(final_position);
1552  if (ssc->mode == STITCH_VERT) {
1553  MEM_freeN(uvfinal_map);
1554  }
1555  MEM_freeN(island_stitch_data);
1556  MEM_freeN(preview_position);
1557 
1558  return 1;
1559 }
1560 
1562 {
1563  for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
1564  if (!stitch_process_data(ssc, ssc->states[ob_index], scene, final)) {
1565  return 0;
1566  }
1567  }
1568 
1569  return 1;
1570 }
1571 
1572 /* Stitch hash initialization functions */
1573 static uint uv_edge_hash(const void *key)
1574 {
1575  const UvEdge *edge = key;
1576  return (BLI_ghashutil_uinthash(edge->uv2) + BLI_ghashutil_uinthash(edge->uv1));
1577 }
1578 
1579 static bool uv_edge_compare(const void *a, const void *b)
1580 {
1581  const UvEdge *edge1 = a;
1582  const UvEdge *edge2 = b;
1583 
1584  if ((edge1->uv1 == edge2->uv1) && (edge1->uv2 == edge2->uv2)) {
1585  return 0;
1586  }
1587  return 1;
1588 }
1589 
1590 /* select all common edges */
1591 static void stitch_select_edge(UvEdge *edge, StitchState *state, int always_select)
1592 {
1593  UvEdge *eiter;
1594  UvEdge **selection_stack = (UvEdge **)state->selection_stack;
1595 
1596  for (eiter = edge->first; eiter; eiter = eiter->next) {
1597  if (eiter->flag & STITCH_SELECTED) {
1598  int i;
1599  if (always_select) {
1600  continue;
1601  }
1602 
1603  eiter->flag &= ~STITCH_SELECTED;
1604  for (i = 0; i < state->selection_size; i++) {
1605  if (selection_stack[i] == eiter) {
1606  (state->selection_size)--;
1607  selection_stack[i] = selection_stack[state->selection_size];
1608  break;
1609  }
1610  }
1611  }
1612  else {
1613  eiter->flag |= STITCH_SELECTED;
1614  selection_stack[state->selection_size++] = eiter;
1615  }
1616  }
1617 }
1618 
1619 /* Select all common uvs */
1620 static void stitch_select_uv(UvElement *element, StitchState *state, int always_select)
1621 {
1622  BMLoop *l;
1623  UvElement *element_iter;
1624  UvElement **selection_stack = (UvElement **)state->selection_stack;
1625 
1626  l = element->l;
1627 
1628  element_iter = state->element_map->vert[BM_elem_index_get(l->v)];
1629  /* first deselect all common uvs */
1630  for (; element_iter; element_iter = element_iter->next) {
1631  if (element_iter->separate) {
1632  /* only separators go to selection */
1633  if (element_iter->flag & STITCH_SELECTED) {
1634  int i;
1635  if (always_select) {
1636  continue;
1637  }
1638 
1639  element_iter->flag &= ~STITCH_SELECTED;
1640  for (i = 0; i < state->selection_size; i++) {
1641  if (selection_stack[i] == element_iter) {
1642  (state->selection_size)--;
1643  selection_stack[i] = selection_stack[state->selection_size];
1644  break;
1645  }
1646  }
1647  }
1648  else {
1649  element_iter->flag |= STITCH_SELECTED;
1650  selection_stack[state->selection_size++] = element_iter;
1651  }
1652  }
1653  }
1654 }
1655 
1656 static void stitch_set_selection_mode(StitchState *state, const char from_stitch_mode)
1657 {
1658  void **old_selection_stack = state->selection_stack;
1659  int old_selection_size = state->selection_size;
1660  state->selection_size = 0;
1661 
1662  if (from_stitch_mode == STITCH_VERT) {
1663  int i;
1664  state->selection_stack = MEM_mallocN(state->total_separate_edges *
1665  sizeof(*state->selection_stack),
1666  "stitch_new_edge_selection_stack");
1667 
1668  /* check if both elements of an edge are selected */
1669  for (i = 0; i < state->total_separate_edges; i++) {
1670  UvEdge *edge = state->edges + i;
1671  UvElement *element1 = state->uvs[edge->uv1];
1672  UvElement *element2 = state->uvs[edge->uv2];
1673 
1674  if ((element1->flag & STITCH_SELECTED) && (element2->flag & STITCH_SELECTED)) {
1675  stitch_select_edge(edge, state, true);
1676  }
1677  }
1678 
1679  /* unselect selected uvelements */
1680  for (i = 0; i < old_selection_size; i++) {
1681  UvElement *element = old_selection_stack[i];
1682 
1683  element->flag &= ~STITCH_SELECTED;
1684  }
1685  }
1686  else {
1687  int i;
1688  state->selection_stack = MEM_mallocN(state->total_separate_uvs *
1689  sizeof(*state->selection_stack),
1690  "stitch_new_vert_selection_stack");
1691 
1692  for (i = 0; i < old_selection_size; i++) {
1693  UvEdge *edge = old_selection_stack[i];
1694  UvElement *element1 = state->uvs[edge->uv1];
1695  UvElement *element2 = state->uvs[edge->uv2];
1696 
1697  stitch_select_uv(element1, state, true);
1698  stitch_select_uv(element2, state, true);
1699 
1700  edge->flag &= ~STITCH_SELECTED;
1701  }
1702  }
1703  MEM_freeN(old_selection_stack);
1704 }
1705 
1707 {
1708  for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
1709  stitch_set_selection_mode(ssc->states[ob_index], ssc->mode);
1710  }
1711 
1712  if (ssc->mode == STITCH_VERT) {
1713  ssc->mode = STITCH_EDGE;
1714  }
1715  else {
1716  ssc->mode = STITCH_VERT;
1717  }
1718 }
1719 
1720 static void stitch_calculate_edge_normal(BMEditMesh *em, UvEdge *edge, float *normal, float aspect)
1721 {
1722  BMLoop *l1 = edge->element->l;
1723  MLoopUV *luv1, *luv2;
1724  float tangent[2];
1725 
1726  luv1 = CustomData_bmesh_get(&em->bm->ldata, l1->head.data, CD_MLOOPUV);
1727  luv2 = CustomData_bmesh_get(&em->bm->ldata, l1->next->head.data, CD_MLOOPUV);
1728 
1729  sub_v2_v2v2(tangent, luv2->uv, luv1->uv);
1730 
1731  tangent[1] /= aspect;
1732 
1733  normal[0] = tangent[1];
1734  normal[1] = -tangent[0];
1735 
1737 }
1738 
1741 static void stitch_draw_vbo(GPUVertBuf *vbo, GPUPrimType prim_type, const float col[4])
1742 {
1745  GPU_batch_uniform_4fv(batch, "color", col);
1748 }
1749 
1750 /* TODO make things pretier : store batches inside StitchPreviewer instead of the bare verts pos */
1751 static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), void *arg)
1752 {
1753 
1755 
1756  for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
1757  int j, index = 0;
1758  uint num_line = 0, num_tri, tri_idx = 0, line_idx = 0;
1759  StitchState *state = ssc->states[ob_index];
1760  StitchPreviewer *stitch_preview = state->stitch_preview;
1761  GPUVertBuf *vbo, *vbo_line;
1762  float col[4];
1763 
1764  static GPUVertFormat format = {0};
1765  static uint pos_id;
1766  if (format.attr_len == 0) {
1768  }
1769 
1771 
1772  /* Static Tris */
1773  if (stitch_preview->static_tris) {
1776  GPU_vertbuf_data_alloc(vbo, stitch_preview->num_static_tris * 3);
1777  for (int i = 0; i < stitch_preview->num_static_tris * 3; i++) {
1778  GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->static_tris[i * 2]);
1779  }
1781  }
1782 
1783  /* Preview Polys */
1784  if (stitch_preview->preview_polys) {
1785  for (int i = 0; i < stitch_preview->num_polys; i++) {
1786  num_line += stitch_preview->uvs_per_polygon[i];
1787  }
1788 
1789  num_tri = num_line - 2 * stitch_preview->num_polys;
1790 
1791  /* we need to convert the polys into triangles / lines */
1794 
1795  GPU_vertbuf_data_alloc(vbo, num_tri * 3);
1796  GPU_vertbuf_data_alloc(vbo_line, num_line * 2);
1797 
1798  for (int i = 0; i < stitch_preview->num_polys; i++) {
1799  BLI_assert(stitch_preview->uvs_per_polygon[i] >= 3);
1800 
1801  /* Start line */
1802  GPU_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index]);
1804  vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + 2]);
1805 
1806  for (j = 1; j < stitch_preview->uvs_per_polygon[i] - 1; j++) {
1807  GPU_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index]);
1809  vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index + (j + 0) * 2]);
1811  vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index + (j + 1) * 2]);
1812 
1814  vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + (j + 0) * 2]);
1816  vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + (j + 1) * 2]);
1817  }
1818 
1819  /* Closing line */
1820  GPU_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index]);
1821  /* j = uvs_per_polygon[i] - 1*/
1823  vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + j * 2]);
1824 
1825  index += stitch_preview->uvs_per_polygon[i] * 2;
1826  }
1827 
1831  stitch_draw_vbo(vbo_line, GPU_PRIM_LINES, col);
1832  }
1833 
1835 
1836  /* draw stitch vert/lines preview */
1837  if (ssc->mode == STITCH_VERT) {
1839 
1842  GPU_vertbuf_data_alloc(vbo, stitch_preview->num_stitchable);
1843  for (int i = 0; i < stitch_preview->num_stitchable; i++) {
1844  GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_stitchable[i * 2]);
1845  }
1847 
1850  GPU_vertbuf_data_alloc(vbo, stitch_preview->num_unstitchable);
1851  for (int i = 0; i < stitch_preview->num_unstitchable; i++) {
1852  GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_unstitchable[i * 2]);
1853  }
1855  }
1856  else {
1859  GPU_vertbuf_data_alloc(vbo, stitch_preview->num_stitchable * 2);
1860  for (int i = 0; i < stitch_preview->num_stitchable * 2; i++) {
1861  GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_stitchable[i * 2]);
1862  }
1864 
1867  GPU_vertbuf_data_alloc(vbo, stitch_preview->num_unstitchable * 2);
1868  for (int i = 0; i < stitch_preview->num_unstitchable * 2; i++) {
1869  GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_unstitchable[i * 2]);
1870  }
1872  }
1873  }
1874 }
1875 
1877 {
1878  UvEdge tmp_edge;
1879 
1880  UvElement *element1 = BM_uv_element_get(state->element_map, l->f, l);
1881  UvElement *element2 = BM_uv_element_get(state->element_map, l->f, l->next);
1882 
1883  int uv1 = state->map[element1 - state->element_map->buf];
1884  int uv2 = state->map[element2 - state->element_map->buf];
1885 
1886  if (uv1 < uv2) {
1887  tmp_edge.uv1 = uv1;
1888  tmp_edge.uv2 = uv2;
1889  }
1890  else {
1891  tmp_edge.uv1 = uv2;
1892  tmp_edge.uv2 = uv1;
1893  }
1894 
1895  return BLI_ghash_lookup(state->edge_hash, &tmp_edge);
1896 }
1897 
1899  wmOperator *op,
1900  StitchStateContainer *ssc,
1901  Object *obedit,
1902  StitchStateInit *state_init)
1903 {
1904  /* for fast edge lookup... */
1905  GHash *edge_hash;
1906  /* ...and actual edge storage */
1907  UvEdge *edges;
1908  int total_edges;
1909  /* maps uvelements to their first coincident uv */
1910  int *map;
1911  int counter = 0, i;
1912  BMFace *efa;
1913  BMLoop *l;
1914  BMIter iter, liter;
1915  GHashIterator gh_iter;
1916  UvEdge *all_edges;
1917  StitchState *state;
1920  float aspx, aspy;
1921 
1922  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1923  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1924 
1925  state = MEM_callocN(sizeof(StitchState), "stitch state obj");
1926 
1927  /* initialize state */
1928  state->obedit = obedit;
1929  state->em = em;
1930 
1931  /* Workaround for sync-select & face-select mode which implies all selected faces are detached,
1932  * for stitch this isn't useful behavior, see T86924. */
1933  const int selectmode_orig = scene->toolsettings->selectmode;
1935 
1936  /* in uv synch selection, all uv's are visible */
1937  if (ts->uv_flag & UV_SYNC_SELECTION) {
1938  state->element_map = BM_uv_element_map_create(state->em->bm, scene, false, false, true, true);
1939  }
1940  else {
1941  state->element_map = BM_uv_element_map_create(state->em->bm, scene, true, false, true, true);
1942  }
1943 
1944  scene->toolsettings->selectmode = selectmode_orig;
1945 
1946  if (!state->element_map) {
1948  return NULL;
1949  }
1950 
1951  ED_uvedit_get_aspect(obedit, &aspx, &aspy);
1952  state->aspect = aspx / aspy;
1953 
1954  /* Count 'unique' uvs */
1955  for (i = 0; i < state->element_map->totalUVs; i++) {
1956  if (state->element_map->buf[i].separate) {
1957  counter++;
1958  }
1959  }
1960 
1961  /* explicitly set preview to NULL,
1962  * to avoid deleting an invalid pointer on stitch_process_data */
1963  state->stitch_preview = NULL;
1964  /* Allocate the unique uv buffers */
1965  state->uvs = MEM_mallocN(sizeof(*state->uvs) * counter, "uv_stitch_unique_uvs");
1966  /* internal uvs need no normals but it is hard and slow to keep a map of
1967  * normals only for boundary uvs, so allocating for all uvs */
1968  state->normals = MEM_callocN(sizeof(*state->normals) * counter * 2, "uv_stitch_normals");
1969  state->total_separate_uvs = counter;
1970  state->map = map = MEM_mallocN(sizeof(*map) * state->element_map->totalUVs,
1971  "uv_stitch_unique_map");
1972  /* Allocate the edge stack */
1973  edge_hash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "stitch_edge_hash");
1974  all_edges = MEM_mallocN(sizeof(*all_edges) * state->element_map->totalUVs, "ssc_edges");
1975 
1976  if (!state->uvs || !map || !edge_hash || !all_edges) {
1978  return NULL;
1979  }
1980 
1981  /* So that we can use this as index for the UvElements */
1982  counter = -1;
1983  /* initialize the unique UVs and map */
1984  for (i = 0; i < em->bm->totvert; i++) {
1985  UvElement *element = state->element_map->vert[i];
1986  for (; element; element = element->next) {
1987  if (element->separate) {
1988  counter++;
1989  state->uvs[counter] = element;
1990  }
1991  /* pointer arithmetic to the rescue, as always :)*/
1992  map[element - state->element_map->buf] = counter;
1993  }
1994  }
1995 
1996  counter = 0;
1997  /* Now, on to generate our uv connectivity data */
1998  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1999  if (!(ts->uv_flag & UV_SYNC_SELECTION) &&
2001  continue;
2002  }
2003 
2004  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2005  UvElement *element = BM_uv_element_get(state->element_map, efa, l);
2006  int offset1, itmp1 = element - state->element_map->buf;
2007  int offset2,
2008  itmp2 = BM_uv_element_get(state->element_map, efa, l->next) - state->element_map->buf;
2009  UvEdge *edge;
2010 
2011  offset1 = map[itmp1];
2012  offset2 = map[itmp2];
2013 
2014  all_edges[counter].next = NULL;
2015  all_edges[counter].first = NULL;
2016  all_edges[counter].flag = 0;
2017  all_edges[counter].element = element;
2018  /* using an order policy, sort uvs according to address space. This avoids
2019  * Having two different UvEdges with the same uvs on different positions */
2020  if (offset1 < offset2) {
2021  all_edges[counter].uv1 = offset1;
2022  all_edges[counter].uv2 = offset2;
2023  }
2024  else {
2025  all_edges[counter].uv1 = offset2;
2026  all_edges[counter].uv2 = offset1;
2027  }
2028 
2029  edge = BLI_ghash_lookup(edge_hash, &all_edges[counter]);
2030  if (edge) {
2031  edge->flag = 0;
2032  }
2033  else {
2034  BLI_ghash_insert(edge_hash, &all_edges[counter], &all_edges[counter]);
2035  all_edges[counter].flag = STITCH_BOUNDARY;
2036  }
2037  counter++;
2038  }
2039  }
2040 
2041  total_edges = BLI_ghash_len(edge_hash);
2042  state->edges = edges = MEM_mallocN(sizeof(*edges) * total_edges, "stitch_edges");
2043 
2044  /* I assume any system will be able to at least allocate an iterator :p */
2045  if (!edges) {
2047  return NULL;
2048  }
2049 
2050  state->total_separate_edges = total_edges;
2051 
2052  /* fill the edges with data */
2053  i = 0;
2054  GHASH_ITER (gh_iter, edge_hash) {
2055  edges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter));
2056  }
2057 
2058  /* cleanup temporary stuff */
2059  MEM_freeN(all_edges);
2060 
2061  BLI_ghash_free(edge_hash, NULL, NULL);
2062 
2063  /* Refill an edge hash to create edge connectivity data. */
2064  state->edge_hash = edge_hash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "stitch_edge_hash");
2065  for (i = 0; i < total_edges; i++) {
2066  BLI_ghash_insert(edge_hash, edges + i, edges + i);
2067  }
2069 
2070  /***** calculate 2D normals for boundary uvs *****/
2071 
2072  /* we use boundary edges to calculate 2D normals.
2073  * to disambiguate the direction of the normal, we also need
2074  * a point "inside" the island, that can be provided by
2075  * the winding of the polygon (assuming counter-clockwise flow). */
2076 
2077  for (i = 0; i < total_edges; i++) {
2078  UvEdge *edge = edges + i;
2079  float normal[2];
2080  if (edge->flag & STITCH_BOUNDARY) {
2081  stitch_calculate_edge_normal(em, edge, normal, state->aspect);
2082 
2083  add_v2_v2(state->normals + edge->uv1 * 2, normal);
2084  add_v2_v2(state->normals + edge->uv2 * 2, normal);
2085 
2086  normalize_v2(state->normals + edge->uv1 * 2);
2087  normalize_v2(state->normals + edge->uv2 * 2);
2088  }
2089  }
2090 
2091  /***** fill selection stack *******/
2092 
2093  state->selection_size = 0;
2094 
2095  /* Load old selection if redoing operator with different settings */
2096  if (state_init != NULL) {
2097  int faceIndex, elementIndex;
2098  UvElement *element;
2099  enum StitchModes stored_mode = RNA_enum_get(op->ptr, "stored_mode");
2100 
2102 
2103  int selected_count = state_init->uv_selected_count;
2104 
2105  if (stored_mode == STITCH_VERT) {
2106  state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) *
2107  state->total_separate_uvs,
2108  "uv_stitch_selection_stack");
2109 
2110  while (selected_count--) {
2111  faceIndex = state_init->to_select[selected_count].faceIndex;
2112  elementIndex = state_init->to_select[selected_count].elementIndex;
2113  efa = BM_face_at_index(em->bm, faceIndex);
2115  state->element_map, efa, BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex));
2117  }
2118  }
2119  else {
2120  state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) *
2121  state->total_separate_edges,
2122  "uv_stitch_selection_stack");
2123 
2124  while (selected_count--) {
2125  UvEdge tmp_edge, *edge;
2126  int uv1, uv2;
2127  faceIndex = state_init->to_select[selected_count].faceIndex;
2128  elementIndex = state_init->to_select[selected_count].elementIndex;
2129  efa = BM_face_at_index(em->bm, faceIndex);
2131  state->element_map, efa, BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex));
2132  uv1 = map[element - state->element_map->buf];
2133 
2135  state->element_map,
2136  efa,
2137  BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, (elementIndex + 1) % efa->len));
2138  uv2 = map[element - state->element_map->buf];
2139 
2140  if (uv1 < uv2) {
2141  tmp_edge.uv1 = uv1;
2142  tmp_edge.uv2 = uv2;
2143  }
2144  else {
2145  tmp_edge.uv1 = uv2;
2146  tmp_edge.uv2 = uv1;
2147  }
2148 
2149  edge = BLI_ghash_lookup(edge_hash, &tmp_edge);
2150 
2151  stitch_select_edge(edge, state, true);
2152  }
2153  }
2154  /* if user has switched the operator mode after operation, we need to convert
2155  * the stored format */
2156  if (ssc->mode != stored_mode) {
2157  stitch_set_selection_mode(state, stored_mode);
2158  }
2159  }
2160  else {
2161  if (ssc->mode == STITCH_VERT) {
2162  state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) *
2163  state->total_separate_uvs,
2164  "uv_stitch_selection_stack");
2165 
2166  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2167  BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
2168  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
2169  UvElement *element = BM_uv_element_get(state->element_map, efa, l);
2170  if (element) {
2172  }
2173  }
2174  }
2175  }
2176  }
2177  else {
2178  state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) *
2179  state->total_separate_edges,
2180  "uv_stitch_selection_stack");
2181 
2182  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2183  if (!(ts->uv_flag & UV_SYNC_SELECTION) && ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) ||
2185  continue;
2186  }
2187 
2188  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2189  if (uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) {
2190  UvEdge *edge = uv_edge_get(l, state);
2191  if (edge) {
2192  stitch_select_edge(edge, state, true);
2193  }
2194  }
2195  }
2196  }
2197  }
2198  }
2199 
2200  /***** initialize static island preview data *****/
2201 
2202  state->tris_per_island = MEM_mallocN(
2203  sizeof(*state->tris_per_island) * state->element_map->totalIslands, "stitch island tris");
2204  for (i = 0; i < state->element_map->totalIslands; i++) {
2205  state->tris_per_island[i] = 0;
2206  }
2207 
2208  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2209  UvElement *element = BM_uv_element_get(state->element_map, efa, BM_FACE_FIRST_LOOP(efa));
2210 
2211  if (element) {
2212  state->tris_per_island[element->island] += (efa->len > 2) ? efa->len - 2 : 0;
2213  }
2214  }
2215 
2216  state->island_is_stitchable = MEM_callocN(sizeof(bool) * state->element_map->totalIslands,
2217  "stitch I stops");
2218  if (!state->island_is_stitchable) {
2220  return NULL;
2221  }
2222 
2223  if (!stitch_process_data(ssc, state, scene, false)) {
2225  return NULL;
2226  }
2227 
2228  return state;
2229 }
2230 
2232 {
2233  StitchState *active_state = ssc->states[ssc->active_object_index];
2234  StitchState *original_active_state = active_state;
2235 
2236  int original_island = ssc->static_island;
2237 
2238  do {
2239  ssc->static_island++;
2240  if (ssc->static_island >= active_state->element_map->totalIslands) {
2241  /* go to next object */
2242  ssc->active_object_index++;
2243  ssc->active_object_index %= ssc->objects_len;
2244 
2245  active_state = ssc->states[ssc->active_object_index];
2246  ssc->static_island = 0;
2247  }
2248 
2249  if (active_state->island_is_stitchable[ssc->static_island]) {
2250  /* We're at an island to make active */
2251  return true;
2252  }
2253  } while (!(active_state == original_active_state && ssc->static_island == original_island));
2254 
2255  return false;
2256 }
2257 
2259 {
2260  ARegion *region = CTX_wm_region(C);
2261  if (!region) {
2262  return 0;
2263  }
2264 
2267 
2268  StitchStateContainer *ssc = MEM_callocN(sizeof(StitchStateContainer), "stitch collection");
2269 
2270  op->customdata = ssc;
2271 
2272  ssc->use_limit = RNA_boolean_get(op->ptr, "use_limit");
2273  ssc->limit_dist = RNA_float_get(op->ptr, "limit");
2274  ssc->snap_islands = RNA_boolean_get(op->ptr, "snap_islands");
2275  ssc->midpoints = RNA_boolean_get(op->ptr, "midpoint_snap");
2276  ssc->clear_seams = RNA_boolean_get(op->ptr, "clear_seams");
2277  ssc->active_object_index = RNA_int_get(op->ptr, "active_object_index");
2278  ssc->static_island = 0;
2279 
2280  if (RNA_struct_property_is_set(op->ptr, "mode")) {
2281  ssc->mode = RNA_enum_get(op->ptr, "mode");
2282  }
2283  else {
2284  if (ts->uv_flag & UV_SYNC_SELECTION) {
2285  if (ts->selectmode & SCE_SELECT_VERTEX) {
2286  ssc->mode = STITCH_VERT;
2287  }
2288  else {
2289  ssc->mode = STITCH_EDGE;
2290  }
2291  }
2292  else {
2293  if (ts->uv_selectmode & UV_SELECT_VERTEX) {
2294  ssc->mode = STITCH_VERT;
2295  }
2296  else {
2297  ssc->mode = STITCH_EDGE;
2298  }
2299  }
2300  }
2301 
2302  ssc->objects_len = 0;
2303  ssc->states = NULL;
2304 
2305  ViewLayer *view_layer = CTX_data_view_layer(C);
2306  View3D *v3d = CTX_wm_view3d(C);
2307  uint objects_len = 0;
2309  view_layer, v3d, &objects_len);
2310 
2311  if (objects_len == 0) {
2312  MEM_freeN(objects);
2313  state_delete_all(ssc);
2314  return 0;
2315  }
2316 
2317  ssc->objects = MEM_callocN(sizeof(Object *) * objects_len, "Object *ssc->objects");
2318  ssc->states = MEM_callocN(sizeof(StitchState *) * objects_len, "StitchState");
2319  ssc->objects_len = 0;
2320 
2321  int *objs_selection_count = NULL;
2322  UvElementID *selected_uvs_arr = NULL;
2323  StitchStateInit *state_init = NULL;
2324 
2325  if (RNA_struct_property_is_set(op->ptr, "selection") &&
2326  RNA_struct_property_is_set(op->ptr, "objects_selection_count")) {
2327  /* Retrieve list of selected UVs, one list contains all selected UVs
2328  * for all objects. */
2329 
2330  objs_selection_count = MEM_mallocN(sizeof(int *) * objects_len, "objects_selection_count");
2331  RNA_int_get_array(op->ptr, "objects_selection_count", objs_selection_count);
2332 
2333  int total_selected = 0;
2334  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2335  total_selected += objs_selection_count[ob_index];
2336  }
2337 
2338  selected_uvs_arr = MEM_callocN(sizeof(UvElementID) * total_selected, "selected_uvs_arr");
2339  int sel_idx = 0;
2340  RNA_BEGIN (op->ptr, itemptr, "selection") {
2341  BLI_assert(sel_idx < total_selected);
2342  selected_uvs_arr[sel_idx].faceIndex = RNA_int_get(&itemptr, "face_index");
2343  selected_uvs_arr[sel_idx].elementIndex = RNA_int_get(&itemptr, "element_index");
2344  sel_idx++;
2345  }
2346  RNA_END;
2347 
2348  RNA_collection_clear(op->ptr, "selection");
2349 
2350  state_init = MEM_callocN(sizeof(StitchStateInit), "UV_init_selected");
2351  state_init->to_select = selected_uvs_arr;
2352  }
2353 
2354  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2355  Object *obedit = objects[ob_index];
2356 
2357  if (state_init != NULL) {
2358  state_init->uv_selected_count = objs_selection_count[ob_index];
2359  }
2360 
2361  StitchState *stitch_state_ob = stitch_init(C, op, ssc, obedit, state_init);
2362 
2363  if (state_init != NULL) {
2364  /* Move pointer to beginning of next object's data. */
2365  state_init->to_select += state_init->uv_selected_count;
2366  }
2367 
2368  if (stitch_state_ob) {
2369  ssc->objects[ssc->objects_len] = obedit;
2370  ssc->states[ssc->objects_len] = stitch_state_ob;
2371  ssc->objects_len++;
2372  }
2373  }
2374 
2375  MEM_freeN(objects);
2376  MEM_SAFE_FREE(selected_uvs_arr);
2377  MEM_SAFE_FREE(objs_selection_count);
2378  MEM_SAFE_FREE(state_init);
2379 
2380  if (ssc->objects_len == 0) {
2381  state_delete_all(ssc);
2382  return 0;
2383  }
2384 
2385  ssc->active_object_index %= ssc->objects_len;
2386 
2387  ssc->static_island = RNA_int_get(op->ptr, "static_island");
2388 
2390  ssc->static_island %= state->element_map->totalIslands;
2391 
2392  /* If the initial active object doesn't have any stitchable islands */
2393  /* then no active island will be seen in the UI. Make sure we're on */
2394  /* a stitchable object and island. */
2395  if (!state->island_is_stitchable[ssc->static_island]) {
2396  goto_next_island(ssc);
2397  state = ssc->states[ssc->active_object_index];
2398  }
2399 
2400  /* process active stitchobj again now that it can detect it's the active stitchobj */
2401  stitch_process_data(ssc, state, scene, false);
2402 
2403  stitch_update_header(ssc, C);
2404 
2406  region->type, stitch_draw, ssc, REGION_DRAW_POST_VIEW);
2407 
2408  return 1;
2409 }
2410 
2411 static int stitch_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2412 {
2413  if (!stitch_init_all(C, op)) {
2414  return OPERATOR_CANCELLED;
2415  }
2416 
2418 
2421  const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
2422 
2424 
2425  for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
2426  StitchState *state = ssc->states[ob_index];
2427  Object *obedit = state->obedit;
2428  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2429 
2430  if (synced_selection && (em->bm->totvertsel == 0)) {
2431  continue;
2432  }
2433 
2435  }
2436 
2437  return OPERATOR_RUNNING_MODAL;
2438 }
2439 
2440 static void stitch_exit(bContext *C, wmOperator *op, int finished)
2441 {
2443  SpaceImage *sima = CTX_wm_space_image(C);
2444  ScrArea *area = CTX_wm_area(C);
2445 
2447 
2448  if (finished) {
2449  RNA_float_set(op->ptr, "limit", ssc->limit_dist);
2450  RNA_boolean_set(op->ptr, "use_limit", ssc->use_limit);
2451  RNA_boolean_set(op->ptr, "snap_islands", ssc->snap_islands);
2452  RNA_boolean_set(op->ptr, "midpoint_snap", ssc->midpoints);
2453  RNA_boolean_set(op->ptr, "clear_seams", ssc->clear_seams);
2454  RNA_enum_set(op->ptr, "mode", ssc->mode);
2455  RNA_enum_set(op->ptr, "stored_mode", ssc->mode);
2456  RNA_int_set(op->ptr, "active_object_index", ssc->active_object_index);
2457 
2458  RNA_int_set(op->ptr, "static_island", ssc->static_island);
2459 
2460  int *objs_selection_count = NULL;
2461  objs_selection_count = MEM_mallocN(sizeof(int *) * ssc->objects_len,
2462  "objects_selection_count");
2463 
2464  /* Store selection for re-execution of stitch
2465  * - Store all selected UVs in "selection"
2466  * - Store how many each object has in "objects_selection_count". */
2467  RNA_collection_clear(op->ptr, "selection");
2468  for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
2469  StitchState *state = ssc->states[ob_index];
2470  Object *obedit = state->obedit;
2471 
2472  PointerRNA itemptr;
2473  for (int i = 0; i < state->selection_size; i++) {
2474  UvElement *element;
2475 
2476  if (ssc->mode == STITCH_VERT) {
2477  element = state->selection_stack[i];
2478  }
2479  else {
2480  element = ((UvEdge *)state->selection_stack[i])->element;
2481  }
2482  RNA_collection_add(op->ptr, "selection", &itemptr);
2483 
2484  RNA_int_set(&itemptr, "face_index", BM_elem_index_get(element->l->f));
2485  RNA_int_set(&itemptr, "element_index", element->loop_of_poly_index);
2486  }
2487  uvedit_live_unwrap_update(sima, scene, obedit);
2488 
2489  objs_selection_count[ob_index] = state->selection_size;
2490  }
2491 
2492  PropertyRNA *prop = RNA_struct_find_property(op->ptr, "objects_selection_count");
2493  RNA_def_property_array(prop, ssc->objects_len);
2494  RNA_int_set_array(op->ptr, "objects_selection_count", objs_selection_count);
2495  MEM_freeN(objs_selection_count);
2496  }
2497 
2498  if (area) {
2500  }
2501 
2503 
2505  const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
2506 
2507  for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
2508  StitchState *state = ssc->states[ob_index];
2509  Object *obedit = state->obedit;
2510  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2511 
2512  if (synced_selection && (em->bm->totvertsel == 0)) {
2513  continue;
2514  }
2515 
2516  DEG_id_tag_update(obedit->data, 0);
2518  }
2519 
2520  state_delete_all(ssc);
2521 
2522  op->customdata = NULL;
2523 }
2524 
2526 {
2527  stitch_exit(C, op, 0);
2528 }
2529 
2531 {
2533 
2534  if (!stitch_init_all(C, op)) {
2535  return OPERATOR_CANCELLED;
2536  }
2538  stitch_exit(C, op, 1);
2539  return OPERATOR_FINISHED;
2540  }
2541  stitch_cancel(C, op);
2542  return OPERATOR_CANCELLED;
2543 }
2544 
2546  Scene *scene,
2547  const wmEvent *event,
2548  StitchStateContainer *ssc)
2549 {
2550  /* add uv under mouse to processed uv's */
2551  float co[2];
2552  ARegion *region = CTX_wm_region(C);
2553  UvNearestHit hit = UV_NEAREST_HIT_INIT_MAX(&region->v2d);
2554 
2555  UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
2556 
2557  if (ssc->mode == STITCH_VERT) {
2558  if (uv_find_nearest_vert_multi(scene, ssc->objects, ssc->objects_len, co, 0.0f, &hit)) {
2559  /* Add vertex to selection, deselect all common uv's of vert other than selected and
2560  * update the preview. This behavior was decided so that you can do stuff like deselect
2561  * the opposite stitchable vertex and the initial still gets deselected */
2562 
2563  /* find StitchState from hit->ob */
2564  StitchState *state = NULL;
2565  for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
2566  if (hit.ob == ssc->objects[ob_index]) {
2567  state = ssc->states[ob_index];
2568  break;
2569  }
2570  }
2571 
2572  /* This works due to setting of tmp in find nearest uv vert */
2573  UvElement *element = BM_uv_element_get(state->element_map, hit.efa, hit.l);
2574  stitch_select_uv(element, state, false);
2575 
2576  return state;
2577  }
2578  }
2579  else if (uv_find_nearest_edge_multi(scene, ssc->objects, ssc->objects_len, co, &hit)) {
2580  /* find StitchState from hit->ob */
2581  StitchState *state = NULL;
2582  for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
2583  if (hit.ob == ssc->objects[ob_index]) {
2584  state = ssc->states[ob_index];
2585  break;
2586  }
2587  }
2588 
2589  UvEdge *edge = uv_edge_get(hit.l, state);
2590  stitch_select_edge(edge, state, false);
2591 
2592  return state;
2593  }
2594 
2595  return NULL;
2596 }
2597 
2598 static int stitch_modal(bContext *C, wmOperator *op, const wmEvent *event)
2599 {
2600  StitchStateContainer *ssc;
2602 
2603  ssc = op->customdata;
2604  StitchState *active_state = ssc->states[ssc->active_object_index];
2605 
2606  switch (event->type) {
2607  case MIDDLEMOUSE:
2608  return OPERATOR_PASS_THROUGH;
2609 
2610  /* Cancel */
2611  case EVT_ESCKEY:
2612  stitch_cancel(C, op);
2613  return OPERATOR_CANCELLED;
2614 
2615  case LEFTMOUSE:
2616  case EVT_PADENTER:
2617  case EVT_RETKEY:
2618  if (event->val == KM_PRESS) {
2619  if (stitch_process_data(ssc, active_state, scene, true)) {
2620  stitch_exit(C, op, 1);
2621  return OPERATOR_FINISHED;
2622  }
2623 
2624  stitch_cancel(C, op);
2625  return OPERATOR_CANCELLED;
2626  }
2627  return OPERATOR_PASS_THROUGH;
2628 
2629  /* Increase limit */
2630  case EVT_PADPLUSKEY:
2631  case WHEELUPMOUSE:
2632  if (event->val == KM_PRESS && event->alt) {
2633  ssc->limit_dist += 0.01f;
2634  if (!stitch_process_data(ssc, active_state, scene, false)) {
2635  stitch_cancel(C, op);
2636  return OPERATOR_CANCELLED;
2637  }
2638  break;
2639  }
2640  else {
2641  return OPERATOR_PASS_THROUGH;
2642  }
2643  /* Decrease limit */
2644  case EVT_PADMINUS:
2645  case WHEELDOWNMOUSE:
2646  if (event->val == KM_PRESS && event->alt) {
2647  ssc->limit_dist -= 0.01f;
2648  ssc->limit_dist = MAX2(0.01f, ssc->limit_dist);
2649  if (!stitch_process_data(ssc, active_state, scene, false)) {
2650  stitch_cancel(C, op);
2651  return OPERATOR_CANCELLED;
2652  }
2653  break;
2654  }
2655  else {
2656  return OPERATOR_PASS_THROUGH;
2657  }
2658 
2659  /* Use Limit (Default off) */
2660  case EVT_LKEY:
2661  if (event->val == KM_PRESS) {
2662  ssc->use_limit = !ssc->use_limit;
2663  if (!stitch_process_data(ssc, active_state, scene, false)) {
2664  stitch_cancel(C, op);
2665  return OPERATOR_CANCELLED;
2666  }
2667  break;
2668  }
2669  return OPERATOR_RUNNING_MODAL;
2670 
2671  case EVT_IKEY:
2672  if (event->val == KM_PRESS) {
2673  /* Move to next island and maybe next object */
2674 
2675  if (goto_next_island(ssc)) {
2676  StitchState *new_active_state = ssc->states[ssc->active_object_index];
2677 
2678  /* active_state is the original active state */
2679  if (active_state != new_active_state) {
2680  if (!stitch_process_data(ssc, active_state, scene, false)) {
2681  stitch_cancel(C, op);
2682  return OPERATOR_CANCELLED;
2683  }
2684  }
2685 
2686  if (!stitch_process_data(ssc, new_active_state, scene, false)) {
2687  stitch_cancel(C, op);
2688  return OPERATOR_CANCELLED;
2689  }
2690  }
2691  break;
2692  }
2693  return OPERATOR_RUNNING_MODAL;
2694 
2695  case EVT_MKEY:
2696  if (event->val == KM_PRESS) {
2697  ssc->midpoints = !ssc->midpoints;
2698  if (!stitch_process_data(ssc, active_state, scene, false)) {
2699  stitch_cancel(C, op);
2700  return OPERATOR_CANCELLED;
2701  }
2702  }
2703  break;
2704 
2705  /* Select geometry */
2706  case RIGHTMOUSE:
2707  if (!event->shift) {
2708  stitch_cancel(C, op);
2709  return OPERATOR_CANCELLED;
2710  }
2711  if (event->val == KM_PRESS) {
2712  StitchState *selected_state = stitch_select(C, scene, event, ssc);
2713 
2714  if (selected_state && !stitch_process_data(ssc, selected_state, scene, false)) {
2715  stitch_cancel(C, op);
2716  return OPERATOR_CANCELLED;
2717  }
2718  break;
2719  }
2720  return OPERATOR_RUNNING_MODAL;
2721 
2722  /* snap islands on/off */
2723  case EVT_SKEY:
2724  if (event->val == KM_PRESS) {
2725  ssc->snap_islands = !ssc->snap_islands;
2726  if (!stitch_process_data(ssc, active_state, scene, false)) {
2727  stitch_cancel(C, op);
2728  return OPERATOR_CANCELLED;
2729  }
2730  break;
2731  }
2732  else {
2733  return OPERATOR_RUNNING_MODAL;
2734  }
2735 
2736  /* switch between edge/vertex mode */
2737  case EVT_TABKEY:
2738  if (event->val == KM_PRESS) {
2740 
2741  if (!stitch_process_data_all(ssc, scene, false)) {
2742  stitch_cancel(C, op);
2743  return OPERATOR_CANCELLED;
2744  }
2745  }
2746  break;
2747 
2748  default:
2749  return OPERATOR_RUNNING_MODAL;
2750  }
2751 
2752  /* if updated settings, renew feedback message */
2753  stitch_update_header(ssc, C);
2755 
2756  return OPERATOR_RUNNING_MODAL;
2757 }
2758 
2760 {
2761  PropertyRNA *prop;
2762 
2763  static const EnumPropertyItem stitch_modes[] = {
2764  {STITCH_VERT, "VERTEX", 0, "Vertex", ""},
2765  {STITCH_EDGE, "EDGE", 0, "Edge", ""},
2766  {0, NULL, 0, NULL, NULL},
2767  };
2768 
2769  /* identifiers */
2770  ot->name = "Stitch";
2771  ot->description = "Stitch selected UV vertices by proximity";
2772  ot->idname = "UV_OT_stitch";
2774 
2775  /* api callbacks */
2776  ot->invoke = stitch_invoke;
2777  ot->modal = stitch_modal;
2778  ot->exec = stitch_exec;
2779  ot->cancel = stitch_cancel;
2781 
2782  /* properties */
2784  ot->srna, "use_limit", 0, "Use Limit", "Stitch UVs within a specified limit distance");
2786  "snap_islands",
2787  1,
2788  "Snap Islands",
2789  "Snap islands together (on edge stitch mode, rotates the islands too)");
2790 
2792  "limit",
2793  0.01f,
2794  0.0f,
2795  FLT_MAX,
2796  "Limit",
2797  "Limit distance in normalized coordinates",
2798  0.0,
2799  FLT_MAX);
2800  RNA_def_int(ot->srna,
2801  "static_island",
2802  0,
2803  0,
2804  INT_MAX,
2805  "Static Island",
2806  "Island that stays in place when stitching islands",
2807  0,
2808  INT_MAX);
2809  RNA_def_int(ot->srna,
2810  "active_object_index",
2811  0,
2812  0,
2813  INT_MAX,
2814  "Active Object",
2815  "Index of the active object",
2816  0,
2817  INT_MAX);
2819  "midpoint_snap",
2820  0,
2821  "Snap at Midpoint",
2822  "UVs are stitched at midpoint instead of at static island");
2823  RNA_def_boolean(ot->srna, "clear_seams", 1, "Clear Seams", "Clear seams of stitched edges");
2824  RNA_def_enum(ot->srna,
2825  "mode",
2826  stitch_modes,
2827  STITCH_VERT,
2828  "Operation Mode",
2829  "Use vertex or edge stitching");
2830  prop = RNA_def_enum(ot->srna,
2831  "stored_mode",
2832  stitch_modes,
2833  STITCH_VERT,
2834  "Stored Operation Mode",
2835  "Use vertex or edge stitching");
2838  ot->srna, "selection", &RNA_SelectedUvElement, "Selection", "");
2839  /* Selection should not be editable or viewed in toolbar */
2841 
2842  /* test should not be editable or viewed in toolbar */
2843  prop = RNA_def_int_array(ot->srna,
2844  "objects_selection_count",
2845  1,
2846  NULL,
2847  0,
2848  INT_MAX,
2849  "Objects Selection Count",
2850  "",
2851  0,
2852  INT_MAX);
2853  RNA_def_property_array(prop, 6);
2855 }
typedef float(TangentPoint)[2]
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:714
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1044
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:760
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
struct SpaceImage * CTX_wm_space_image(const bContext *C)
Definition: context.c:800
CustomData interface, see also DNA_customdata_types.h.
void * CustomData_bmesh_get(const struct CustomData *data, void *block, int type)
int CustomData_get_offset(const struct CustomData *data, int type)
BMEditMesh * BKE_editmesh_from_object(struct Object *ob)
Return the BMEditMesh for a given object.
Definition: editmesh.c:85
#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, v3d, r_len)
Definition: BKE_layer.h:434
#define BLI_assert(a)
Definition: BLI_assert.h:58
BLI_INLINE void * BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.h:146
unsigned int BLI_ghashutil_uinthash(unsigned int key)
#define GHASH_ITER(gh_iter_, ghash_)
Definition: BLI_ghash.h:169
GHash * BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:718
unsigned int BLI_ghash_len(GHash *gh) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:744
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:756
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:1008
void * BLI_ghash_lookup(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:803
MINLINE float max_ff(float a, float b)
MINLINE float min_ff(float a, float b)
#define M_PI_2
Definition: BLI_math_base.h:41
#define M_PI
Definition: BLI_math_base.h:38
void mul_v2_m2v2(float r[2], const float M[2][2], const float v[2])
Definition: math_matrix.c:780
void angle_to_mat2(float R[2][2], const float angle)
MINLINE void sub_v2_v2(float r[2], const float a[2])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void add_v2_v2(float r[2], const float a[2])
MINLINE void negate_v2_v2(float r[2], const float a[2])
MINLINE float cross_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE float dot_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v2(float r[2])
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned char uchar
Definition: BLI_sys_types.h:86
unsigned int uint
Definition: BLI_sys_types.h:83
unsigned short ushort
Definition: BLI_sys_types.h:84
#define SWAP(type, a, b)
#define UNUSED(x)
#define MAX2(a, b)
#define TIP_(msgid)
void DEG_id_tag_update(struct ID *id, int flag)
@ CD_MLOOPUV
Object is a sort of wrapper for general info.
#define UV_SYNC_SELECTION
#define SCE_SELECT_VERTEX
#define UV_SELECT_VERTEX
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
struct UvElement * BM_uv_element_get(struct UvElementMap *map, struct BMFace *efa, struct BMLoop *l)
struct UvElementMap * BM_uv_element_map_create(struct BMesh *bm, const struct Scene *scene, const bool face_selected, const bool uv_selected, const bool use_winding, const bool do_islands)
void BM_uv_element_map_free(struct UvElementMap *element_map)
void ED_region_tag_redraw(struct ARegion *region)
Definition: area.c:667
bool ED_operator_uvedit(struct bContext *C)
Definition: screen_ops.c:511
void ED_workspace_status_text(struct bContext *C, const char *str)
Definition: area.c:840
#define REGION_DRAW_POST_VIEW
Definition: ED_space_api.h:66
void * ED_region_draw_cb_activate(struct ARegionType *art, void(*draw)(const struct bContext *, struct ARegion *, void *), void *customdata, int type)
Definition: spacetypes.c:238
void ED_region_draw_cb_exit(struct ARegionType *, void *)
Definition: spacetypes.c:253
void ED_uvedit_get_aspect(struct Object *obedit, float *r_aspx, float *r_aspy)
bool uvedit_uv_select_test(const struct Scene *scene, struct BMLoop *l, const int cd_loop_uv_offset)
void uvedit_uv_select_enable(const struct Scene *scene, struct BMEditMesh *em, struct BMLoop *l, const bool do_history, const int cd_loop_uv_offset)
bool uvedit_edge_select_test(const struct Scene *scene, struct BMLoop *l, const int cd_loop_uv_offset)
GPUBatch
Definition: GPU_batch.h:93
void GPU_batch_discard(GPUBatch *)
Definition: gpu_batch.cc:127
void GPU_batch_program_set_builtin(GPUBatch *batch, eGPUBuiltinShader shader_id)
Definition: gpu_batch.cc:299
GPUBatch * GPU_batch_create_ex(GPUPrimType prim, GPUVertBuf *vert, GPUIndexBuf *elem, eGPUBatchFlag owns_flag)
Definition: gpu_batch.cc:60
void GPU_batch_draw(GPUBatch *batch)
Definition: gpu_batch.cc:234
#define GPU_batch_uniform_4fv(batch, name, val)
Definition: GPU_batch.h:142
@ GPU_BATCH_OWNS_VBO
Definition: GPU_batch.h:45
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
GPUPrimType
Definition: GPU_primitive.h:34
@ GPU_PRIM_LINES
Definition: GPU_primitive.h:36
@ GPU_PRIM_POINTS
Definition: GPU_primitive.h:35
@ GPU_PRIM_TRIS
Definition: GPU_primitive.h:37
@ GPU_SHADER_2D_UNIFORM_COLOR
Definition: GPU_shader.h:171
@ GPU_BLEND_NONE
Definition: GPU_state.h:55
@ GPU_BLEND_ALPHA
Definition: GPU_state.h:57
void GPU_blend(eGPUBlend blend)
Definition: gpu_state.cc:55
void GPU_point_size(float size)
Definition: gpu_state.cc:179
#define GPU_vertbuf_create_with_format(format)
struct GPUVertBuf GPUVertBuf
void GPU_vertbuf_data_alloc(GPUVertBuf *, uint v_len)
void GPU_vertbuf_attr_set(GPUVertBuf *, uint a_idx, uint v_idx, const void *data)
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define RNA_BEGIN(sptr, itemptr, propname)
Definition: RNA_access.h:1248
#define RNA_END
Definition: RNA_access.h:1255
StructRNA RNA_SelectedUvElement
@ PROP_HIDDEN
Definition: RNA_types.h:202
#define C
Definition: RandGen.cpp:39
#define UI_MAX_DRAW_STR
Definition: UI_interface.h:90
@ TH_STITCH_PREVIEW_UNSTITCHABLE
Definition: UI_resources.h:261
@ TH_VERTEX_SIZE
Definition: UI_resources.h:97
@ TH_STITCH_PREVIEW_EDGE
Definition: UI_resources.h:258
@ TH_STITCH_PREVIEW_ACTIVE
Definition: UI_resources.h:262
@ TH_STITCH_PREVIEW_STITCHABLE
Definition: UI_resources.h:260
@ TH_STITCH_PREVIEW_FACE
Definition: UI_resources.h:257
void UI_GetThemeColor4fv(int colorid, float col[4])
Definition: resources.c:1199
float UI_GetThemeValuef(int colorid)
Definition: resources.c:1164
void UI_view2d_region_to_view(const struct View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
#define NC_GEOM
Definition: WM_types.h:294
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
#define ND_DATA
Definition: WM_types.h:408
#define KM_PRESS
Definition: WM_types.h:242
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_ELEM_HIDDEN
Definition: bmesh_class.h:472
@ BM_ELEM_SEAM
Definition: bmesh_class.h:473
@ BM_ELEM_SELECT
Definition: bmesh_class.h:471
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:553
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:124
#define BM_elem_flag_disable(ele, hflag)
Definition: bmesh_inline.h:29
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
void * BM_iter_at_index(BMesh *bm, const char itype, void *data, int index)
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_FACE
#define BM_ITER_ELEM_INDEX(ele, iter, data, itype, indexvar)
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.c:2276
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.c:2152
BLI_INLINE BMFace * BM_face_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:110
ATTR_WARN_UNUSED_RESULT const void * element
ATTR_WARN_UNUSED_RESULT const BMLoop * l
Scene scene
GPUBatch * batch
Definition: drawnode.c:3779
#define str(s)
uint col
IconTextureDrawCall normal
#define acosf(x)
#define fabsf(x)
format
Definition: logImageCore.h:47
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static ulong state[N]
static unsigned a[3]
Definition: RandGen.cpp:92
static void area(int d1, int d2, int e1, int e2, float weights[2])
void RNA_int_set_array(PointerRNA *ptr, const char *name, const int *values)
Definition: rna_access.c:6343
void RNA_int_get_array(PointerRNA *ptr, const char *name, int *values)
Definition: rna_access.c:6331
void RNA_collection_clear(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6622
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
Definition: rna_access.c:6272
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
Definition: rna_access.c:6319
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:866
void RNA_collection_add(PointerRNA *ptr, const char *name, PointerRNA *r_value)
Definition: rna_access.c:6610
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6308
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6355
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
Definition: rna_access.c:6366
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:6685
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
Definition: rna_access.c:6413
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6402
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3825
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3481
PropertyRNA * RNA_def_int_array(StructOrFunctionRNA *cont_, const char *identifier, int len, const int *default_value, int hardmin, int hardmax, const char *ui_name, const char *ui_description, int softmin, int softmax)
Definition: rna_define.c:3643
PropertyRNA * RNA_def_collection_runtime(StructOrFunctionRNA *cont_, const char *identifier, StructRNA *type, const char *ui_name, const char *ui_description)
Definition: rna_define.c:4210
void RNA_def_property_array(PropertyRNA *prop, int length)
Definition: rna_define.c:1568
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1512
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, int default_value, int hardmin, int hardmax, const char *ui_name, const char *ui_description, int softmin, int softmax)
Definition: rna_define.c:3585
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3771
struct ARegionType * type
struct BMesh * bm
Definition: BKE_editmesh.h:52
int len
Definition: bmesh_class.h:279
void * data
Definition: bmesh_class.h:63
BMHeader head
Definition: bmesh_class.h:157
struct BMVert * v
Definition: bmesh_class.h:165
struct BMEdge * e
Definition: bmesh_class.h:176
struct BMLoop * prev
Definition: bmesh_class.h:245
struct BMFace * f
Definition: bmesh_class.h:183
struct BMLoop * next
Definition: bmesh_class.h:245
int totvert
Definition: bmesh_class.h:297
int totvertsel
Definition: bmesh_class.h:298
CustomData ldata
Definition: bmesh_class.h:337
int totface
Definition: bmesh_class.h:297
void * data
struct ToolSettings * toolsettings
UvElementID * to_select
bool * island_is_stitchable
UvElementMap * element_map
BMEditMesh * em
StitchPreviewer * stitch_preview
UvElement ** uvs
struct UvEdge * next
char flag
Definition: sculpt_uv.c:77
uint uv1
Definition: sculpt_uv.c:73
UvElement * element
struct UvEdge * first
uint uv2
Definition: sculpt_uv.c:74
struct UvElement * buf
struct UvElement ** vert
unsigned char flag
unsigned int island
unsigned short loop_of_poly_index
struct UvElement * next
struct BMLoop * l
struct BMLoop * l
Definition: uvedit_intern.h:43
struct Object * ob
Definition: uvedit_intern.h:40
struct BMFace * efa
Definition: uvedit_intern.h:42
short shift
Definition: WM_types.h:618
short val
Definition: WM_types.h:579
int mval[2]
Definition: WM_types.h:583
short alt
Definition: WM_types.h:618
short type
Definition: WM_types.h:577
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:768
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:760
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
struct PointerRNA * ptr
bool uv_find_nearest_vert_multi(struct Scene *scene, struct Object **objects, const uint objects_len, const float co[2], const float penalty_dist, struct UvNearestHit *hit)
#define UV_NEAREST_HIT_INIT_MAX(v2d)
Definition: uvedit_intern.h:65
void uvedit_live_unwrap_update(struct SpaceImage *sima, struct Scene *scene, struct Object *obedit)
Definition: uvedit_ops.c:193
bool uv_find_nearest_edge_multi(struct Scene *scene, struct Object **objects, const uint objects_len, const float co[2], struct UvNearestHit *hit)
static bool stitch_check_edges_state_stitchable(UvEdge *edge, UvEdge *edge_iter, StitchStateContainer *ssc, StitchState *state)
static int stitch_init_all(bContext *C, wmOperator *op)
static void stitch_propagate_uv_final_position(Scene *scene, UvElement *element, int index, PreviewPosition *preview_position, UVVertAverage *final_position, StitchStateContainer *ssc, StitchState *state, const bool final)
#define STITCH_STITCHABLE
#define STITCH_SELECTED
#define STITCH_PROCESSED
static void stitch_switch_selection_mode_all(StitchStateContainer *ssc)
static void stitch_select_edge(UvEdge *edge, StitchState *state, int always_select)
struct UvElementID UvElementID
struct StitchPreviewer StitchPreviewer
static void stitch_exit(bContext *C, wmOperator *op, int finished)
static void determine_uv_edge_stitchability(UvEdge *edge, StitchStateContainer *ssc, StitchState *state, IslandStitchData *island_stitch_data)
static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), void *arg)
struct UvEdge UvEdge
static bool stitch_check_uvs_stitchable(UvElement *element, UvElement *element_iter, StitchStateContainer *ssc, StitchState *state)
static UvEdge * uv_edge_get(BMLoop *l, StitchState *state)
void UV_OT_stitch(wmOperatorType *ot)
static void stitch_island_calculate_edge_rotation(UvEdge *edge, StitchStateContainer *ssc, StitchState *state, UVVertAverage *uv_average, const uint *uvfinal_map, IslandStitchData *island_stitch_data)
static void stitch_update_header(StitchStateContainer *ssc, bContext *C)
static int stitch_process_data_all(StitchStateContainer *ssc, Scene *scene, int final)
static void stitch_draw_vbo(GPUVertBuf *vbo, GPUPrimType prim_type, const float col[4])
static void determine_uv_stitchability(UvElement *element, StitchStateContainer *ssc, StitchState *state, IslandStitchData *island_stitch_data)
static void stitch_uv_edge_generate_linked_edges(GHash *edge_hash, StitchState *state)
struct StitchState StitchState
static bool uv_edge_compare(const void *a, const void *b)
static void state_delete_all(StitchStateContainer *ssc)
static int getNumOfIslandUvs(UvElementMap *elementMap, int island)
static void stitch_set_face_preview_buffer_position(BMFace *efa, StitchPreviewer *preview, PreviewPosition *preview_position)
struct UVVertAverage UVVertAverage
static bool stitch_check_uvs_state_stitchable(UvElement *element, UvElement *element_iter, StitchStateContainer *ssc, StitchState *state)
static int stitch_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
struct IslandStitchData IslandStitchData
static void stitch_uv_rotate(const float mat[2][2], const float medianPoint[2], float uv[2], float aspect)
@ STITCH_VERT
@ STITCH_EDGE
static void stitch_cancel(bContext *C, wmOperator *op)
static bool goto_next_island(StitchStateContainer *ssc)
#define STITCH_STITCHABLE_CANDIDATE
struct StitchStateInit StitchStateInit
static uint uv_edge_hash(const void *key)
struct StitchStateContainer StitchStateContainer
static bool stitch_check_edges_stitchable(UvEdge *edge, UvEdge *edge_iter, StitchStateContainer *ssc, StitchState *state)
static void stitch_island_calculate_vert_rotation(UvElement *element, StitchStateContainer *ssc, StitchState *state, IslandStitchData *island_stitch_data)
static void stitch_validate_uv_stitchability(UvElement *element, StitchStateContainer *ssc, StitchState *state, IslandStitchData *island_stitch_data, PreviewPosition *preview_position)
#define STITCH_NO_PREVIEW
static void stitch_preview_delete(StitchPreviewer *stitch_preview)
struct PreviewPosition PreviewPosition
static void stitch_calculate_edge_normal(BMEditMesh *em, UvEdge *edge, float *normal, float aspect)
static StitchState * stitch_init(bContext *C, wmOperator *op, StitchStateContainer *ssc, Object *obedit, StitchStateInit *state_init)
static void stitch_validate_edge_stitchability(UvEdge *edge, StitchStateContainer *ssc, StitchState *state, IslandStitchData *island_stitch_data, PreviewPosition *preview_position)
#define STITCH_BOUNDARY
static StitchPreviewer * stitch_preview_init(void)
static void stitch_setup_face_preview_for_uv_group(UvElement *element, StitchStateContainer *ssc, StitchState *state, IslandStitchData *island_stitch_data, PreviewPosition *preview_position)
static void stitch_set_selection_mode(StitchState *state, const char from_stitch_mode)
static StitchState * stitch_select(bContext *C, Scene *scene, const wmEvent *event, StitchStateContainer *ssc)
static int stitch_exec(bContext *C, wmOperator *op)
static void state_delete(StitchState *state)
static void stitch_select_uv(UvElement *element, StitchState *state, int always_select)
static int stitch_process_data(StitchStateContainer *ssc, StitchState *state, Scene *scene, int final)
static void stitch_calculate_island_snapping(StitchState *state, PreviewPosition *preview_position, StitchPreviewer *preview, IslandStitchData *island_stitch_data, int final)
static int stitch_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ RIGHTMOUSE
@ EVT_SKEY
@ EVT_IKEY
@ EVT_TABKEY
@ WHEELUPMOUSE
@ EVT_PADENTER
@ WHEELDOWNMOUSE
@ EVT_MKEY
@ EVT_PADMINUS
@ LEFTMOUSE
@ MIDDLEMOUSE
@ EVT_ESCKEY
@ EVT_LKEY
@ EVT_PADPLUSKEY
@ EVT_RETKEY
wmOperatorType * ot
Definition: wm_files.c:3156
const char * WM_bool_as_string(bool test)
Definition: wm_keymap.c:2003