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