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