Blender V5.0
bmesh_uvselect.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "MEM_guardedalloc.h"
10
11#include "DNA_scene_types.h"
12
13#include "BLI_listbase.h"
14#include "BLI_math_bits.h"
15
16#include "bmesh.hh"
17#include "bmesh_structure.hh"
18
19/* -------------------------------------------------------------------- */
22
24{
25 /* In practically all cases it's best to check #BM_ELEM_HIDDEN
26 * In this case the intent is to re-generate the selection, so clear all. */
27 BMIter iter;
28 BMFace *f;
29 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
30 BMLoop *l_iter, *l_first;
31 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
32 do {
34 } while ((l_iter = l_iter->next) != l_first);
36 }
37}
38
40
41/* -------------------------------------------------------------------- */
44
54
59
61
62/* -------------------------------------------------------------------- */
65
67 const char hflag,
68 const int cd_loop_uv_offset)
69{
71 BMVert *v = l->v;
72 BLI_assert(v->e);
73 const BMEdge *e_iter, *e_first;
74 e_iter = e_first = v->e;
75 do {
76 if (e_iter->l == nullptr) {
77 continue;
78 }
79 BMLoop *l_first = e_iter->l;
80 BMLoop *l_iter = l_first;
81 do {
82 if (BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
83 continue;
84 }
85 if (l_iter->v != v) {
86 continue;
87 }
88 if (l_iter != l) {
89 if (BM_elem_flag_test(l_iter, hflag)) {
90 if (BM_loop_uv_share_vert_check(l, l_iter, cd_loop_uv_offset)) {
91 return true;
92 }
93 }
94 }
95 } while ((l_iter = l_iter->radial_next) != l_first);
96 } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
97 return false;
98}
99
101 const char hflag,
102 const int cd_loop_uv_offset)
103{
105 BMVert *v = l->v;
106 BLI_assert(v->e);
107 const BMEdge *e_iter, *e_first;
108 e_iter = e_first = v->e;
109 do {
110 if (e_iter->l == nullptr) {
111 continue;
112 }
113 BMLoop *l_first = e_iter->l;
114 BMLoop *l_iter = l_first;
115 do {
116 if (BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
117 continue;
118 }
119 if (l_iter->v != v) {
120 continue;
121 }
122 /* Connected to a selected edge. */
123 if (l_iter != l) {
124 if (BM_elem_flag_test(l_iter, hflag) || BM_elem_flag_test(l_iter->prev, hflag)) {
125 if (BM_loop_uv_share_vert_check(l, l_iter, cd_loop_uv_offset)) {
126 return true;
127 }
128 }
129 }
130 } while ((l_iter = l_iter->radial_next) != l_first);
131 } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
132 return false;
133}
134
136 const char hflag,
137 const int cd_loop_uv_offset)
138{
140 BMVert *v = l->v;
141 BLI_assert(v->e);
142 const BMEdge *e_iter, *e_first;
143 e_iter = e_first = v->e;
144 do {
145 if (e_iter->l == nullptr) {
146 continue;
147 }
148 BMLoop *l_first = e_iter->l;
149 BMLoop *l_iter = l_first;
150 do {
151 if (BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
152 continue;
153 }
154 if (l_iter->v != v) {
155 continue;
156 }
157 /* Connected to a selected edge. */
158 if (l_iter != l) {
159 if (((!BM_elem_flag_test(l_iter->e, BM_ELEM_HIDDEN)) &&
160 BM_elem_flag_test(l_iter->e, hflag)) ||
161 ((!BM_elem_flag_test(l_iter->prev->e, BM_ELEM_HIDDEN)) &&
162 BM_elem_flag_test(l_iter->prev->e, hflag)))
163 {
164 if (BM_loop_uv_share_vert_check(l, l_iter, cd_loop_uv_offset)) {
165 return true;
166 }
167 }
168 }
169 } while ((l_iter = l_iter->radial_next) != l_first);
170 } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
171 return false;
172}
173
175 const char hflag,
176 const int cd_loop_uv_offset)
177{
179 BMVert *v = l->v;
180 BLI_assert(v->e);
181 const BMEdge *e_iter, *e_first;
182 e_iter = e_first = v->e;
183 do {
184 if (e_iter->l == nullptr) {
185 continue;
186 }
187 BMLoop *l_first = e_iter->l;
188 BMLoop *l_iter = l_first;
189 do {
190 if (BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
191 continue;
192 }
193 if (l_iter->v != v) {
194 continue;
195 }
196 if (l_iter != l) {
197 if (BM_elem_flag_test(l_iter->f, hflag)) {
198 if (BM_loop_uv_share_vert_check(l, l_iter, cd_loop_uv_offset)) {
199 return true;
200 }
201 }
202 }
203 } while ((l_iter = l_iter->radial_next) != l_first);
204 } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
205 return false;
206}
207
209 const char hflag,
210 const int cd_loop_uv_offset)
211{
213 BMLoop *l_iter = l;
214 do {
215 if (BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
216 continue;
217 }
218 if (l_iter != l) {
219 if (BM_elem_flag_test(l_iter, hflag)) {
220 if (BM_loop_uv_share_edge_check(l, l_iter, cd_loop_uv_offset)) {
221 return true;
222 }
223 }
224 }
225 } while ((l_iter = l_iter->radial_next) != l);
226 return false;
227}
228
230 const char hflag,
231 const int cd_loop_uv_offset)
232{
234 BMLoop *l_iter = l;
235 do {
236 if (BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
237 continue;
238 }
239 if (l_iter != l) {
240 if (BM_elem_flag_test(l_iter->f, hflag)) {
241 if (BM_loop_uv_share_edge_check(l, l_iter, cd_loop_uv_offset)) {
242 return true;
243 }
244 }
245 }
246 } while ((l_iter = l_iter->radial_next) != l);
247 return false;
248}
249
251{
253 return false;
254 }
255 BMLoop *l_iter, *l_first;
256 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
257 do {
259 return false;
260 }
261 } while ((l_iter = l_iter->next) != l_first);
262 return true;
263}
264
266
267/* -------------------------------------------------------------------- */
270
272{
273 /* Only select if it's valid, otherwise the result wont be used. */
274 BLI_assert(bm->uv_select_sync_valid);
276
277 /* Selecting when hidden must be prevented by the caller.
278 * Allow de-selecting as this may be useful at times. */
280
281 /* NOTE: don't do any flushing here as it's too expensive to walk over connected geometry.
282 * These can be handled in separate operations. */
284}
285
287{
288 /* Only select if it's valid, otherwise the result wont be used. */
289 BLI_assert(bm->uv_select_sync_valid);
291
292 /* Selecting when hidden must be prevented by the caller.
293 * Allow de-selecting as this may be useful at times. */
295
296 /* NOTE: don't do any flushing here as it's too expensive to walk over connected geometry.
297 * These can be handled in separate operations. */
299}
300
308
310{
311 /* Only select if it's valid, otherwise the result wont be used. */
312 BLI_assert(bm->uv_select_sync_valid);
314
315 /* Selecting when hidden must be prevented by the caller.
316 * Allow de-selecting as this may be useful at times. */
318
319 /* NOTE: don't do any flushing here as it's too expensive to walk over connected geometry.
320 * These can be handled in separate operations. */
322}
323
325{
327 BMLoop *l_iter, *l_first;
328 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
329 do {
332 } while ((l_iter = l_iter->next) != l_first);
333}
334
336{
337 if (bm->uv_select_sync_valid == false) {
338 return false;
339 }
340 bm->uv_select_sync_valid = false;
341 return true;
342}
343
345
346/* -------------------------------------------------------------------- */
349
351 BMLoop *l,
352 bool select,
353 const int cd_loop_uv_offset)
354{
356
357 BMVert *v = l->v;
358 BLI_assert(v->e);
359 const BMEdge *e_iter, *e_first;
360 e_iter = e_first = v->e;
361 do {
362 if (e_iter->l == nullptr) {
363 continue;
364 }
365 BMLoop *l_first = e_iter->l;
366 BMLoop *l_iter = l_first;
367 do {
368 if (BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
369 continue;
370 }
371 if (l_iter->v != v) {
372 continue;
373 }
374 if (l_iter != l) {
376 if (BM_loop_uv_share_vert_check(l, l_iter, cd_loop_uv_offset)) {
378 }
379 }
380 }
381 } while ((l_iter = l_iter->radial_next) != l_first);
382 } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
383}
384
386 BMLoop *l,
387 bool select,
388 const int cd_loop_uv_offset)
389{
391
392 BMLoop *l_iter = l->radial_next;
393 /* Check it's not a boundary. */
394 if (l_iter != l) {
395 do {
396 if (BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
397 continue;
398 }
400 if (BM_loop_uv_share_edge_check(l, l_iter, cd_loop_uv_offset)) {
402 }
403 }
404 } while ((l_iter = l_iter->radial_next) != l);
405 }
406}
407
408void BM_face_uvselect_set_shared(BMesh *bm, BMFace *f, bool select, const int cd_loop_uv_offset)
409{
411 BMLoop *l_iter, *l_first;
412 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
413 do {
414 BM_loop_vert_uvselect_set_shared(bm, l_iter, select, cd_loop_uv_offset);
415 BM_loop_edge_uvselect_set_shared(bm, l_iter, select, cd_loop_uv_offset);
416 } while ((l_iter = l_iter->next) != l_first);
417}
418
420 bool select,
421 const int cd_loop_uv_offset,
422 const blender::Span<BMLoop *> loop_verts,
423 const blender::Span<BMLoop *> loop_edges,
425{
426 /* TODO: this could be optimized to reduce traversal of connected UV's for every element. */
427
428 for (BMLoop *l_vert : loop_verts) {
429 BM_loop_vert_uvselect_set_shared(bm, l_vert, select, cd_loop_uv_offset);
430 }
431 for (BMLoop *l_edge : loop_edges) {
432 BM_loop_edge_uvselect_set_shared(bm, l_edge, select, cd_loop_uv_offset);
433
434 if (select) {
435 BM_loop_vert_uvselect_set_shared(bm, l_edge, select, cd_loop_uv_offset);
436 BM_loop_vert_uvselect_set_shared(bm, l_edge->next, select, cd_loop_uv_offset);
437 }
438 }
439 for (BMFace *f : faces) {
440 if (select) {
441 BM_face_uvselect_set_shared(bm, f, select, cd_loop_uv_offset);
442 }
443 else {
445 }
446 }
447
448 /* Only de-select shared elements if they are no longer connected to a selection. */
449 if (!select) {
450 for (BMLoop *l_edge : loop_edges) {
451 if (BM_elem_flag_test(l_edge->f, BM_ELEM_HIDDEN)) {
452 continue;
453 }
454 /* If any of the vertices from the edges are no longer connected to a selected edge
455 * de-select the entire vertex.. */
456 for (BMLoop *l_edge_vert : {l_edge, l_edge->next}) {
458 l_edge_vert, BM_ELEM_SELECT_UV_EDGE, cd_loop_uv_offset))
459 {
460 BM_loop_vert_uvselect_set_shared(bm, l_edge_vert, false, cd_loop_uv_offset);
461 }
462 }
463 }
464
465 /* De-select edge pass. */
466 for (BMFace *f : faces) {
468 continue;
469 }
470
471 BMLoop *l_iter, *l_first;
472 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
473 do {
474 if (!BM_elem_flag_test(l_iter, BM_ELEM_SELECT_UV)) {
475 /* Already handled. */
476 continue;
477 }
478 if (!BM_loop_edge_uvselect_check_other_face(l_iter, BM_ELEM_SELECT_UV, cd_loop_uv_offset))
479 {
480 BM_loop_edge_uvselect_set_shared(bm, l_iter, false, cd_loop_uv_offset);
481 }
482 } while ((l_iter = l_iter->next) != l_first);
483 }
484
485 /* De-select vert pass. */
486 for (BMFace *f : faces) {
488 continue;
489 }
490 BMLoop *l_iter, *l_first;
491 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
492 do {
494 /* Already handled. */
495 continue;
496 }
498 l_iter, BM_ELEM_SELECT_UV_EDGE, cd_loop_uv_offset))
499 {
500 BM_loop_vert_uvselect_set_shared(bm, l_iter, false, cd_loop_uv_offset);
501 }
502 } while ((l_iter = l_iter->next) != l_first);
503 }
504 }
505}
506
508
509/* -------------------------------------------------------------------- */
529
531 BMVert *v,
532 const bool select,
533 const BMUVSelectPickParams & /*uv_pick_params*/,
534 bool caller_handles_edge_or_face_mode)
535{
536 if (caller_handles_edge_or_face_mode == false) {
537 /* With de-selection, isolated vertices/edges wont be de-selected.
538 * In practice users should not be picking edges when in face select mode. */
539 BLI_assert_msg(bm->selectmode & (SCE_SELECT_VERTEX),
540 "Picking verts in edge or face-select mode is not supported.");
541 }
542 /* NOTE: it doesn't make sense to check `uv_pick_params.shared` in this context because,
543 * unlike edges and faces, a vertex is logically connected to all corners that use it,
544 * so there is no way to use the UV coordinates to differentiate one UV region from another. */
545
547 return;
548 }
549
550 /* Must be connected to edges. */
551 if (v->e == nullptr) {
552 return;
553 }
554
555 if (select) {
556 const BMEdge *e_iter, *e_first;
557 e_iter = e_first = v->e;
558 do {
559 if (e_iter->l == nullptr) {
560 continue;
561 }
562 BMLoop *l_radial_iter, *l_radial_first;
563 l_radial_iter = l_radial_first = e_iter->l;
564 do {
565 if (BM_elem_flag_test(l_radial_iter->f, BM_ELEM_HIDDEN)) {
566 continue;
567 }
568 if (v != l_radial_iter->v) {
569 continue;
570 }
571 /* Select vertex. */
572 BM_loop_vert_uvselect_set_noflush(bm, l_radial_iter, true);
573
574 /* Select edges if adjacent vertices are selected. */
575 if (BM_elem_flag_test(l_radial_iter->next, BM_ELEM_SELECT_UV)) {
576 BM_loop_edge_uvselect_set_noflush(bm, l_radial_iter, true);
577 }
578 if (BM_elem_flag_test(l_radial_iter->prev, BM_ELEM_SELECT_UV)) {
579 BM_loop_edge_uvselect_set_noflush(bm, l_radial_iter->prev, true);
580 }
581 /* Select face if all edges are selected. */
582 if (!BM_elem_flag_test(l_radial_iter->f, BM_ELEM_HIDDEN) &&
583 !BM_elem_flag_test(l_radial_iter->f, BM_ELEM_SELECT_UV))
584 {
585 if (BM_face_uvselect_check_edges_all(l_radial_iter->f)) {
586 BM_face_uvselect_set_noflush(bm, l_radial_iter->f, true);
587 }
588 }
589 } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
590 } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
591 }
592 else {
593 const BMEdge *e_iter, *e_first;
594 e_iter = e_first = v->e;
595 do {
596 if (e_iter->l == nullptr) {
597 continue;
598 }
599 BMLoop *l_radial_iter, *l_radial_first;
600 l_radial_iter = l_radial_first = e_iter->l;
601 do {
602 if (BM_elem_flag_test(l_radial_iter->f, BM_ELEM_HIDDEN)) {
603 continue;
604 }
605 if (v != l_radial_iter->v) {
606 continue;
607 }
608 /* Deselect vertex. */
609 BM_loop_vert_uvselect_set_noflush(bm, l_radial_iter, false);
610 /* Deselect edges. */
611 BM_loop_edge_uvselect_set_noflush(bm, l_radial_iter, false);
612 BM_loop_edge_uvselect_set_noflush(bm, l_radial_iter->prev, false);
613 /* Deselect connected face. */
614 BM_face_uvselect_set_noflush(bm, l_radial_iter->f, false);
615 } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
616 } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
617 }
618}
619
621 BMEdge *e,
622 const bool select,
623 const BMUVSelectPickParams &uv_pick_params,
624 const bool caller_handles_face_mode)
625{
626 if (caller_handles_face_mode == false) {
627 /* With de-selection, isolated vertices/edges wont be de-selected.
628 * In practice users should not be picking edges when in face select mode. */
630 "Picking edges in face-select mode is not supported.");
631 }
632
634 return;
635 }
636
637 /* Must be connected to faces. */
638 if (e->l == nullptr) {
639 return;
640 }
641
642 if (uv_pick_params.shared == false) {
643 BMLoop *l_iter, *l_first;
644
645 if (select) {
646 bool any_faces_unselected = false;
647 l_iter = l_first = e->l;
648 do {
649 if (BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
650 continue;
651 }
652
654
657
658 if (any_faces_unselected == false) {
659 if (!BM_elem_flag_test(l_iter->f, BM_ELEM_SELECT_UV)) {
660 any_faces_unselected = true;
661 }
662 }
663 } while ((l_iter = l_iter->radial_next) != l_first);
664
665 /* Flush selection to faces when all edges in connected faces are now selected. */
666 if (any_faces_unselected) {
667 l_iter = l_first = e->l;
668 do {
669 if (BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
670 continue;
671 }
672 if (!BM_elem_flag_test(l_iter->f, BM_ELEM_SELECT_UV)) {
673 if (BM_face_uvselect_check_edges_all(l_iter->f)) {
674 BM_face_uvselect_set_noflush(bm, l_iter->f, true);
675 }
676 }
677 } while ((l_iter = l_iter->radial_next) != l_first);
678 }
679 }
680 else {
681 l_iter = l_first = e->l;
682 do {
683 if (BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
684 continue;
685 }
689 }
692 }
693 BM_face_uvselect_set_noflush(bm, l_iter->f, false);
694 } while ((l_iter = l_iter->radial_next) != l_first);
695 }
696 return;
697 }
698
699 /* NOTE(@ideasman42): this is awkward as the edge may reference multiple island bounds.
700 * - De-selecting will de-select all which makes sense.
701 * - Selecting will also select all which is not likely to be all that useful for users.
702 *
703 * We could attempt to use the surrounding selection to *guess* which UV island selection
704 * to extend but this seems error prone as it depends on the order elements are selected
705 * so it's it only likely to work in some situations.
706 *
707 * To *properly* solve this we would be better off to support picking edge+face (loop)
708 * combinations from the 3D viewport, so picking the edge would determine the loop which would
709 * be selected, but this is a much bigger change.
710 *
711 * In practice users are likely to prefer face selection when working with UV islands anyway. */
712
713 BMLoop *l_iter, *l_first;
714
715 if (select) {
716 bool any_faces_unselected = false;
717 l_iter = l_first = e->l;
718 do {
719 if (BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
720 continue;
721 }
722
724
727
728 if (any_faces_unselected == false) {
729 if (!BM_elem_flag_test(l_iter->f, BM_ELEM_SELECT_UV)) {
730 any_faces_unselected = true;
731 }
732 }
733 } while ((l_iter = l_iter->radial_next) != l_first);
734
735 /* Flush selection to faces when all edges in connected faces are now selected. */
736 if (any_faces_unselected) {
737 l_iter = l_first = e->l;
738 do {
739 if (BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
740 continue;
741 }
742 if (!BM_elem_flag_test(l_iter->f, BM_ELEM_SELECT_UV)) {
743 if (BM_face_uvselect_check_edges_all(l_iter->f)) {
744 BM_face_uvselect_set_noflush(bm, l_iter->f, true);
745 }
746 }
747 } while ((l_iter = l_iter->radial_next) != l_first);
748 }
749 }
750 else {
751 l_iter = l_first = e->l;
752 do {
753 if (BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
754 continue;
755 }
759 }
762 }
763 BM_face_uvselect_set_noflush(bm, l_iter->f, false);
764 } while ((l_iter = l_iter->radial_next) != l_first);
765
766 /* Ensure connected vertices remain selected when they are connected to selected edges. */
767 l_iter = l_first = e->l;
768 do {
769 if (BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
770 continue;
771 }
772 for (BMLoop *l_edge_vert : {l_iter, l_iter->next}) {
773 if (BM_elem_flag_test(l_edge_vert, BM_ELEM_SELECT_UV)) {
774 /* This was not de-selected. */
775 continue;
776 }
778 l_edge_vert, BM_ELEM_SELECT_UV_EDGE, uv_pick_params.cd_loop_uv_offset))
779 {
780 BM_loop_vert_uvselect_set_noflush(bm, l_edge_vert, true);
781 }
782 else {
783 /* It's possible there are isolated selected vertices,
784 * although in edge select mode this should not happen. */
786 bm, l_edge_vert, false, uv_pick_params.cd_loop_uv_offset);
787 }
788 }
789 } while ((l_iter = l_iter->radial_next) != l_first);
790 }
791}
792
794 BMFace *f,
795 const bool select,
796 const BMUVSelectPickParams &uv_pick_params)
797{
798 /* Picking faces is valid in all selection modes. */
800 return;
801 }
802
803 BMLoop *l_iter, *l_first;
804
805 if (uv_pick_params.shared == false) {
807 return;
808 }
809
810 if (select) {
812
813 /* Setting these values first. */
814 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
815 do {
818 } while ((l_iter = l_iter->next) != l_first);
819
820 /* Set other values. */
821 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
822 do {
823 BM_loop_vert_uvselect_set_shared(bm, l_iter, true, uv_pick_params.cd_loop_uv_offset);
824 BM_loop_edge_uvselect_set_shared(bm, l_iter, true, uv_pick_params.cd_loop_uv_offset);
825 } while ((l_iter = l_iter->next) != l_first);
826 }
827 else {
829
830 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
831 do {
834 /* Vertex. */
836 l_iter, BM_ELEM_SELECT_UV, uv_pick_params.cd_loop_uv_offset))
837 {
839 }
840 else {
841 BM_loop_vert_uvselect_set_shared(bm, l_iter, false, uv_pick_params.cd_loop_uv_offset);
842 }
843 /* Edge. */
845 l_iter, BM_ELEM_SELECT_UV, uv_pick_params.cd_loop_uv_offset))
846 {
848 }
849 else {
850 BM_loop_edge_uvselect_set_shared(bm, l_iter, false, uv_pick_params.cd_loop_uv_offset);
851 }
852 } while ((l_iter = l_iter->next) != l_first);
853 }
854}
855
857 BMVert *v,
858 bool select,
860{
861 const bool caller_handles_edge_or_face_mode = false;
862 bm_vert_uvselect_set_pick(bm, v, select, params, caller_handles_edge_or_face_mode);
863}
865 BMEdge *e,
866 bool select,
868{
869 const bool caller_handles_face_mode = false;
870 bm_edge_uvselect_set_pick(bm, e, select, params, caller_handles_face_mode);
871}
873 BMFace *f,
874 bool select,
876{
877 /* Picking faces is valid in all modes. */
879}
880
894 const short select_mode,
895 const int cd_loop_uv_offset,
896 const bool shared,
897 const bool check_verts,
898 const bool check_edges)
899{
900 if (!(check_verts || check_edges)) {
901 return;
902 }
903
904 /* No additional work needed. */
905 bool do_check = false;
906 if (select_mode & SCE_SELECT_VERTEX) {
907 /* Pass. */
908 }
909 else if (select_mode & SCE_SELECT_EDGE) {
910 if (check_verts) {
911 do_check = true;
912 }
913 }
914 else if (select_mode & SCE_SELECT_FACE) {
915 if (check_verts || check_edges) {
916 do_check = true;
917 }
918 }
919
920 if (do_check == false) {
921 return;
922 }
923
924 /* This requires a fairly specific kind of flushing.
925 * - It's only necessary to flush down (faces -> edges, edges -> verts).
926 * - Only select/deselect is needed.
927 * Do this inline.
928 */
929 if (select_mode & SCE_SELECT_EDGE) {
930 /* Deselect isolated vertices. */
931 BMIter iter;
932 BMFace *f;
933 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
935 continue;
936 }
937 /* Only handle faces that are partially selected. */
939 continue;
940 }
941 BMLoop *l_iter, *l_first;
942 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
943 do {
945 /* Skip the UV check if either edge is selected. */
948 {
950 l_iter, BM_ELEM_SELECT_UV_EDGE, cd_loop_uv_offset))
951 {
953 }
954 }
955 } while ((l_iter = l_iter->next) != l_first);
956 }
957 }
958 else if (select_mode & SCE_SELECT_FACE) {
959 /* Deselect isolated vertices & edges. */
960 BMIter iter;
961 BMFace *f;
962 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
964 continue;
965 }
966 /* Only handle faces that are partially selected. */
968 continue;
969 }
970 BMLoop *l_iter, *l_first;
971 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
972 do {
975 l_iter, BM_ELEM_SELECT_UV, cd_loop_uv_offset))
976 {
978 }
979 }
980 } while ((l_iter = l_iter->next) != l_first);
981 bool e_prev_select = BM_elem_flag_test(l_iter->prev, BM_ELEM_SELECT_UV_EDGE);
982 l_iter = l_first;
983 do {
984 const bool e_iter_select = BM_elem_flag_test(l_iter, BM_ELEM_SELECT_UV_EDGE);
985 /* Skip the UV check if either edge is selected. */
986 if (BM_elem_flag_test(l_iter, BM_ELEM_SELECT_UV) && !(e_prev_select || e_iter_select)) {
988 l_iter, BM_ELEM_SELECT_UV, cd_loop_uv_offset))
989 {
991 }
992 }
993 e_prev_select = e_iter_select;
994 } while ((l_iter = l_iter->next) != l_first);
995 }
996 }
997}
998
1000 const bool select,
1003 const blender::VectorList<BMEdge *> &edges,
1005{
1006 const bool check_verts = !verts.is_empty();
1007 const bool check_edges = !edges.is_empty();
1008
1009 /* TODO(@ideasman42): select picking may be slow because it does flushing too.
1010 * Although in practice it seems fast-enough. This should be handled more efficiently. */
1011
1012 for (BMVert *v : verts) {
1014 }
1015 for (BMEdge *e : edges) {
1017 }
1018 for (BMFace *f : faces) {
1020 }
1021
1023 bm, bm->selectmode, params.cd_loop_uv_offset, params.shared, check_verts, check_edges);
1024}
1025
1027 bool select,
1032{
1033 const bool check_verts = !verts.is_empty();
1034 const bool check_edges = !edges.is_empty();
1035
1036 for (BMVert *v : verts) {
1038 }
1039 for (BMEdge *e : edges) {
1041 }
1042 for (BMFace *f : faces) {
1044 }
1045
1047 bm, bm->selectmode, params.cd_loop_uv_offset, params.shared, check_verts, check_edges);
1048}
1049
1051
1052/* -------------------------------------------------------------------- */
1055
1057{
1058 BMIter iter;
1059 BMFace *f;
1060 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1062 continue;
1063 }
1064
1065 BMLoop *l_iter, *l_first;
1066 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1067 bool all_select = true;
1068 do {
1069 if (BM_elem_flag_test(l_iter, BM_ELEM_SELECT_UV) &&
1071 {
1073 }
1074 else {
1075 all_select = false;
1076 }
1077 } while ((l_iter = l_iter->next) != l_first);
1078 if (all_select) {
1080 }
1081 }
1082}
1083
1085{
1086 BMIter iter;
1087 BMFace *f;
1088 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1090 continue;
1091 }
1092
1093 BMLoop *l_iter, *l_first;
1094 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1095 bool all_select = true;
1096 do {
1097 if (BM_elem_flag_test(l_iter, BM_ELEM_SELECT_UV) &&
1099 {
1100 /* Pass. */
1101 }
1102 else {
1103 BM_loop_edge_uvselect_set_noflush(bm, l_iter, false);
1104 all_select = false;
1105 }
1106 } while ((l_iter = l_iter->next) != l_first);
1107 if (all_select == false) {
1109 }
1110 }
1111}
1112
1114{
1115 BMIter iter;
1116 BMFace *f;
1117 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1119 continue;
1120 }
1121
1122 BMLoop *l_iter, *l_first;
1123 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1124 bool all_select = true;
1125 do {
1127 BM_loop_edge_uvselect_set(bm, l_iter, true);
1128 }
1129 else {
1130 all_select = false;
1131 }
1132 } while ((l_iter = l_iter->next) != l_first);
1133 if (all_select) {
1135 }
1136 }
1137}
1138
1140{
1141 BMIter iter;
1142 BMFace *f;
1143 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1145 continue;
1146 }
1147
1148 BMLoop *l_iter, *l_first;
1149 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1150 bool all_select = true;
1151 do {
1153 l_iter,
1156
1158 /* Pass. */
1159 }
1160 else {
1161 BM_loop_edge_uvselect_set_noflush(bm, l_iter, false);
1162 all_select = false;
1163 }
1164 } while ((l_iter = l_iter->next) != l_first);
1165 if (all_select == false) {
1167 }
1168 }
1169}
1170
1172{
1173 BMIter iter;
1174 BMFace *f;
1175 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1177 continue;
1178 }
1179
1181 continue;
1182 }
1183 BMLoop *l_iter, *l_first;
1184 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1185 do {
1188 } while ((l_iter = l_iter->next) != l_first);
1189 }
1190}
1191
1193{
1194 BMIter iter;
1195 BMFace *f;
1196 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1198 continue;
1199 }
1200
1202 continue;
1203 }
1204 BMLoop *l_iter, *l_first;
1205 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1206 do {
1207 BM_loop_vert_uvselect_set_noflush(bm, l_iter, false);
1208 BM_loop_edge_uvselect_set_noflush(bm, l_iter, false);
1209 } while ((l_iter = l_iter->next) != l_first);
1210 }
1211}
1212
1213void BM_mesh_uvselect_flush_shared_only_select(BMesh *bm, const int cd_loop_uv_offset)
1214{
1215 BLI_assert(cd_loop_uv_offset >= 0);
1216 BMIter iter;
1217 BMFace *f;
1218 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1220 continue;
1221 }
1222
1223 BMLoop *l_iter, *l_first;
1224 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1225 do {
1226 if (!BM_elem_flag_test(l_iter, BM_ELEM_SELECT_UV)) {
1228 l_iter, BM_ELEM_SELECT_UV, cd_loop_uv_offset))
1229 {
1231 }
1232 }
1235 l_iter, BM_ELEM_SELECT_UV_EDGE, cd_loop_uv_offset))
1236 {
1238 }
1239 }
1240 } while ((l_iter = l_iter->next) != l_first);
1241 }
1242}
1243
1244void BM_mesh_uvselect_flush_shared_only_deselect(BMesh *bm, const int cd_loop_uv_offset)
1245{
1246 BLI_assert(cd_loop_uv_offset >= 0);
1247 BMIter iter;
1248 BMFace *f;
1249 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1251 continue;
1252 }
1253
1254 BMLoop *l_iter, *l_first;
1255 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1256 do {
1257 if (BM_elem_flag_test(l_iter, BM_ELEM_SELECT_UV)) {
1259 l_iter, BM_ELEM_SELECT_UV, cd_loop_uv_offset))
1260 {
1261 BM_loop_vert_uvselect_set_noflush(bm, l_iter, false);
1262 }
1263 }
1266 l_iter, BM_ELEM_SELECT_UV_EDGE, cd_loop_uv_offset))
1267 {
1268 BM_loop_edge_uvselect_set_noflush(bm, l_iter, false);
1269 }
1270 }
1271 } while ((l_iter = l_iter->next) != l_first);
1272 }
1273}
1274
1276
1277/* -------------------------------------------------------------------- */
1280
1282{
1283 BMIter iter;
1284 BMFace *f;
1285 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1287 continue;
1288 }
1289
1290 bool select_all = true;
1291 BMLoop *l_iter, *l_first;
1292 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1293 do {
1294 const bool select = (BM_elem_flag_test(l_iter, BM_ELEM_SELECT_UV) &&
1297 if (select == false) {
1298 select_all = false;
1299 }
1300 } while ((l_iter = l_iter->next) != l_first);
1301 BM_face_uvselect_set_noflush(bm, f, select_all);
1302 }
1303}
1304
1306{
1307 BMIter iter;
1308 BMFace *f;
1309
1310 /* Clear vert/face select. */
1311 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1313 continue;
1314 }
1315
1316 if (flush_down) {
1317 BMLoop *l_iter, *l_first;
1318 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1319 do {
1320 BM_loop_vert_uvselect_set_noflush(bm, l_iter, false);
1321 } while ((l_iter = l_iter->next) != l_first);
1322 }
1324 }
1325
1326 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1328 continue;
1329 }
1330
1331 bool select_all = true;
1332 BMLoop *l_iter, *l_first;
1333 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1334 do {
1335 const bool select_edge = BM_elem_flag_test(l_iter, BM_ELEM_SELECT_UV_EDGE);
1336 if (select_edge) {
1337 if (flush_down) {
1340 }
1341 }
1342 else {
1343 select_all = false;
1344 }
1345 } while ((l_iter = l_iter->next) != l_first);
1346 if (select_all) {
1348 }
1349 }
1350}
1351
1353{
1354 if (!flush_down) {
1355 return; /* NOP. */
1356 }
1357
1358 BMIter iter;
1359 BMFace *f;
1360 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1362 continue;
1363 }
1364
1365 const bool select_face = BM_elem_flag_test(f, BM_ELEM_SELECT_UV);
1366 BMLoop *l_iter, *l_first;
1367 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1368 do {
1369 BM_loop_vert_uvselect_set_noflush(bm, l_iter, select_face);
1370 BM_loop_edge_uvselect_set_noflush(bm, l_iter, select_face);
1371 } while ((l_iter = l_iter->next) != l_first);
1372 }
1373}
1374
1384
1386
1387/* -------------------------------------------------------------------- */
1390
1391void BM_mesh_uvselect_mode_flush_ex(BMesh *bm, const short selectmode, const bool flush_down)
1392{
1393 if (selectmode & SCE_SELECT_VERTEX) {
1395 }
1396 else if (selectmode & SCE_SELECT_EDGE) {
1398 }
1399 else {
1401 }
1402}
1403
1405{
1406 BM_mesh_uvselect_mode_flush_ex(bm, bm->selectmode, false);
1407}
1408
1410{
1411 if (bm->selectmode & SCE_SELECT_VERTEX) {
1413 }
1414 else if (bm->selectmode & SCE_SELECT_EDGE) {
1416 }
1417 else {
1418 /* Pass (nothing to do for faces). */
1419 }
1420}
1421
1423 const short selectmode_old,
1424 const short selectmode_new,
1425 const int cd_loop_uv_offset)
1426{
1427
1428 if (highest_order_bit_s(selectmode_old) >= highest_order_bit_s(selectmode_new)) {
1429
1430 if ((selectmode_old & SCE_SELECT_VERTEX) == 0 && (selectmode_new & SCE_SELECT_VERTEX)) {
1431 /* When changing from edge/face to vertex selection,
1432 * new edges/faces may be selected based on the vertex selection. */
1434 }
1435 else if ((selectmode_old & SCE_SELECT_EDGE) == 0 && (selectmode_new & SCE_SELECT_EDGE)) {
1436 /* When changing from face to edge selection,
1437 * new faces may be selected based on the edge selection. */
1439 }
1440
1441 /* Pass, no need to do anything when moving from edge to vertex mode (for e.g.). */
1442 return;
1443 }
1444
1445 bool do_flush_deselect_down = false;
1446 if (selectmode_old & SCE_SELECT_VERTEX) {
1447 if ((selectmode_new & SCE_SELECT_VERTEX) == 0) {
1448 do_flush_deselect_down = true;
1449 }
1450 }
1451 else if (selectmode_old & SCE_SELECT_EDGE) {
1452 if ((selectmode_new & SCE_SELECT_EDGE) == 0) {
1453 do_flush_deselect_down = true;
1454 }
1455 }
1456
1457 if (do_flush_deselect_down == false) {
1458 return;
1459 }
1460
1461 /* Perform two passes:
1462 *
1463 * - De-select all elements where the underlying elements are not selected.
1464 * - De select any isolated elements.
1465 *
1466 * NOTE: As the mesh will have already had it's isolated elements de-selected,
1467 * it may seem like this pass shouldn't be needed in UV space,
1468 * however a vert/edge may be isolated in UV space while being connected to a
1469 * selected edge/face in 3D space.
1470 */
1471
1472 /* First pass: match underlying mesh. */
1473 BMIter iter;
1474 BMFace *f;
1475 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1477 continue;
1478 }
1479
1480 BMLoop *l_iter, *l_first;
1481 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1482 bool select_face = true;
1483 do {
1484 if (BM_elem_flag_test(l_iter, BM_ELEM_SELECT_UV)) {
1485 if (!BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
1487 }
1488 }
1490 if (!BM_elem_flag_test(l_iter->e, BM_ELEM_SELECT)) {
1492 select_face = false;
1493 }
1494 }
1495 else {
1496 select_face = false;
1497 }
1498 } while ((l_iter = l_iter->next) != l_first);
1499
1500 if (select_face == false) {
1502 }
1503 }
1504
1505 /* Second Pass: Ensure isolated elements are not selected. */
1506 if (cd_loop_uv_offset != -1) {
1507 const bool shared = true;
1508 const bool check_verts = (bm->totvertsel != 0);
1509 const bool check_edges = (bm->totedgesel != 0);
1511 bm, selectmode_new, cd_loop_uv_offset, shared, check_verts, check_edges);
1512 }
1513}
1514
1515void BM_mesh_uvselect_flush_post_subdivide(BMesh *bm, const int cd_loop_uv_offset)
1516{
1517 {
1518 BMIter iter;
1519 BMFace *f;
1520 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1522 BM_face_uvselect_set(bm, f, true);
1523 }
1524 }
1525 }
1526
1527 const bool use_edges = bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE);
1528 if (use_edges) {
1529 BMIter iter;
1530 BMEdge *e;
1531 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
1532 if (e->l == nullptr) {
1533 continue;
1534 }
1536 /* This will have been handled if an attached face is selected. */
1538 {
1539 BMLoop *l_radial_iter, *l_radial_first;
1540 l_radial_iter = l_radial_first = e->l;
1541 do {
1542 BM_loop_edge_uvselect_set(bm, l_radial_iter, true);
1543 } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
1544 }
1545 }
1546 }
1547
1548 /* Now select any "shared" UV's that are connected to an edge or face. */
1549 if (cd_loop_uv_offset != -1) {
1550 BMIter iter;
1551 BMFace *f;
1552 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1554 continue;
1555 }
1557 continue;
1558 }
1559 BMLoop *l_iter, *l_first;
1560
1561 /* Setting these values first. */
1562 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1563 do {
1564 /* With vertex select mode, only handle vertices, then flush to edges -> faces. */
1565 if ((bm->selectmode & SCE_SELECT_VERTEX) == 0) {
1566 /* Check edges first, since a selected edge also indicates a selected vertex. */
1569 l_iter, BM_ELEM_SELECT_UV_EDGE, cd_loop_uv_offset))
1570 {
1571 /* Check the other radial edge. */
1572 BM_loop_edge_uvselect_set(bm, l_iter, true);
1573 }
1574 }
1575 /* Check the other radial vertex (a selected edge will have done this). */
1576 if (!BM_elem_flag_test(l_iter, BM_ELEM_SELECT_UV)) {
1578 l_iter, BM_ELEM_SELECT_UV, cd_loop_uv_offset))
1579 {
1581 }
1582 }
1583 } while ((l_iter = l_iter->next) != l_first);
1584 }
1585 }
1586
1587 /* It's possible selecting a vertex or edge will cause other elements to have become selected.
1588 * Flush up if necessary. */
1590}
1591
1593
1594/* -------------------------------------------------------------------- */
1597
1598/* Sticky Vertex. */
1599
1601{
1602 BMIter iter;
1603 BMFace *f;
1604
1605 /* UV select flags may be dirty, overwrite all. */
1606 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1608 continue;
1609 }
1610 BMLoop *l_iter, *l_first;
1611 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1612 do {
1613 const bool v_select = BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT);
1614 const bool e_select = BM_elem_flag_test(l_iter->e, BM_ELEM_SELECT);
1615 BM_elem_flag_set(l_iter, BM_ELEM_SELECT_UV, v_select);
1616 BM_elem_flag_set(l_iter, BM_ELEM_SELECT_UV_EDGE, e_select);
1617 } while ((l_iter = l_iter->next) != l_first);
1619 }
1620 bm->uv_select_sync_valid = true;
1621}
1622
1624{
1625 BMIter iter;
1626 BMFace *f;
1627
1628 /* Clearing all makes the following logic simpler as
1629 * since we only need to select UV's connected to selected edges. */
1631
1632 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1634 continue;
1635 }
1636
1637 BMLoop *l_iter, *l_first;
1638 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1639 do {
1640 if (BM_elem_flag_test(l_iter->e, BM_ELEM_SELECT)) {
1642 for (BMLoop *l_edge_vert : {l_iter, l_iter->next}) {
1643 if (!BM_elem_flag_test(l_edge_vert, BM_ELEM_SELECT_UV)) {
1645 }
1646 }
1647 }
1648 } while ((l_iter = l_iter->next) != l_first);
1649
1652 }
1653 }
1654 bm->uv_select_sync_valid = true;
1655}
1656
1658{
1659 BMIter iter;
1660 BMFace *f;
1661
1662 /* Clearing all makes the following logic simpler as
1663 * since we only need to select UV's connected to selected edges. */
1665
1666 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1668 continue;
1669 }
1670
1672 BMLoop *l_iter, *l_first;
1673 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1674 do {
1677
1678 } while ((l_iter = l_iter->next) != l_first);
1680 }
1681 }
1682 bm->uv_select_sync_valid = true;
1683}
1684
1685/* Sticky Location. */
1686
1688 BMesh *bm, const int /*cd_loop_uv_offset*/)
1689{
1690 /* In this particular case use the same logic for sticky vertices,
1691 * unlike faces & edges we can't know which island a selected vertex belongs to.
1692 *
1693 * NOTE: arguably this is only true for an isolated vertex selection,
1694 * if there are surrounding selected edges/faces the vertex could only select UV's
1695 * connected to those selected regions. However, if this logic was followed (at-run-time)
1696 * it would mean that de-selecting a face could suddenly cause the vertex
1697 * (attached to that face on another UV island) to become selected.
1698 * Since that would be unexpected for users - just use this simple logic here. */
1700}
1701
1703 BMesh *bm, const int cd_loop_uv_offset)
1704{
1705 BMIter iter;
1706 BMFace *f;
1707
1708 /* UV select flags may be dirty, overwrite all. */
1709 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1711 continue;
1712 }
1713
1714 BMLoop *l_iter, *l_first;
1715 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1716 bool e_prev_select = BM_elem_flag_test(l_iter->prev->e, BM_ELEM_SELECT);
1717 do {
1718 const bool e_iter_select = BM_elem_flag_test(l_iter->e, BM_ELEM_SELECT);
1719 const bool v_iter_select = (BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT) &&
1720 ((e_prev_select || e_iter_select) ||
1721 /* This is a more expensive check, order last. */
1723 l_iter, BM_ELEM_SELECT, cd_loop_uv_offset)));
1724
1725 BM_elem_flag_set(l_iter, BM_ELEM_SELECT_UV, v_iter_select);
1726 BM_elem_flag_set(l_iter, BM_ELEM_SELECT_UV_EDGE, e_iter_select);
1727 e_prev_select = e_iter_select;
1728 } while ((l_iter = l_iter->next) != l_first);
1729
1730 const bool f_select = BM_elem_flag_test(f, BM_ELEM_SELECT);
1731 BM_elem_flag_set(f, BM_ELEM_SELECT_UV, f_select);
1732 }
1733 bm->uv_select_sync_valid = true;
1734}
1735
1737 BMesh *bm, const int cd_loop_uv_offset)
1738{
1739 BMIter iter;
1740 BMFace *f;
1741
1742 /* UV select flags may be dirty, overwrite all. */
1743 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1745 continue;
1746 }
1747
1749 BMLoop *l_iter, *l_first;
1750 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1751 do {
1753 } while ((l_iter = l_iter->next) != l_first);
1755 }
1756 else {
1757 BMLoop *l_iter, *l_first;
1758 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1759 do {
1760 const bool v_iter_select = (BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT) &&
1762 l_iter, BM_ELEM_SELECT, cd_loop_uv_offset));
1763 const bool e_iter_select = (BM_elem_flag_test(l_iter->e, BM_ELEM_SELECT) &&
1765 l_iter, BM_ELEM_SELECT, cd_loop_uv_offset));
1766
1767 BM_elem_flag_set(l_iter, BM_ELEM_SELECT_UV, v_iter_select);
1768 BM_elem_flag_set(l_iter, BM_ELEM_SELECT_UV_EDGE, e_iter_select);
1769 } while ((l_iter = l_iter->next) != l_first);
1771 }
1772 }
1773 bm->uv_select_sync_valid = true;
1774}
1775
1776/* Public API. */
1777
1779{
1780 if (bm->selectmode & SCE_SELECT_VERTEX) {
1782 }
1783 else if (bm->selectmode & SCE_SELECT_EDGE) {
1785 }
1786 else { /* `SCE_SELECT_FACE` */
1788 }
1789
1790 BLI_assert(bm->uv_select_sync_valid);
1791}
1792
1794{
1795 /* The mode is ignored when sticky selection is disabled,
1796 * Always use the selection from the mesh. */
1798 BLI_assert(bm->uv_select_sync_valid);
1799}
1800
1802{
1803 if (bm->selectmode & SCE_SELECT_VERTEX) {
1805 }
1806 else if (bm->selectmode & SCE_SELECT_EDGE) {
1808 }
1809 else { /* `SCE_SELECT_FACE` */
1811 }
1812 BLI_assert(bm->uv_select_sync_valid);
1813}
1814
1816{
1817 BLI_assert(bm->uv_select_sync_valid);
1818
1819 /* Prevent clearing the selection from removing all selection history.
1820 * This will be validated after flushing. */
1822
1824
1825 if (bm->selectmode & SCE_SELECT_VERTEX) {
1826 /* Simple, no need to worry about edge selection. */
1827
1828 /* Copy loop-vert to vert, then flush. */
1829 BMIter iter;
1830 BMFace *f;
1831 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1833 continue;
1834 }
1835
1836 BMLoop *l_iter, *l_first;
1837 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1838 do {
1839 if (BM_elem_flag_test(l_iter, BM_ELEM_SELECT_UV)) {
1840 BM_vert_select_set(bm, l_iter->v, true);
1841 }
1842 } while ((l_iter = l_iter->next) != l_first);
1843 }
1844
1846 }
1847 else if (bm->selectmode & SCE_SELECT_EDGE) {
1848 BMIter iter;
1849 BMFace *f;
1850 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1852 continue;
1853 }
1854
1855 BMLoop *l_iter, *l_first;
1856 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1857 /* Technically this should only need to check the edge
1858 * because when a vertex isn't selected, it's connected edges shouldn't be.
1859 * Check both in the unlikely case of an invalid selection. */
1860 bool face_select = true;
1861
1862 do {
1863 /* This requires the edges to have already been flushed to the vertices (assert next). */
1864 if (BM_elem_flag_test(l_iter, BM_ELEM_SELECT_UV)) {
1865 BM_vert_select_set(bm, l_iter->v, true);
1866 }
1867 else {
1868 face_select = false;
1869 }
1870
1872 /* If this fails, we've missed flushing. */
1875 BM_edge_select_set(bm, l_iter->e, true);
1876 }
1877 else {
1878 face_select = false;
1879 }
1880 } while ((l_iter = l_iter->next) != l_first);
1881 if (face_select) {
1883 }
1884 }
1885
1886 /* It's possible that a face which is *not* UV-selected
1887 * ends up with all it's edges selected.
1888 * Perform the edge to face flush inline. */
1889 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1891 continue;
1892 }
1893
1894 /* If the face is hidden, we can't selected,
1895 * If the face is already selected, it can be skipped here. */
1897 continue;
1898 }
1899 bool face_select = true;
1900 BMLoop *l_iter, *l_first;
1901 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1902 do {
1903 if (!BM_elem_flag_test(l_iter->e, BM_ELEM_SELECT)) {
1904 face_select = false;
1905 break;
1906 }
1907 } while ((l_iter = l_iter->next) != l_first);
1908
1909 if (face_select) {
1911 }
1912 }
1913 }
1914 else { /* `bm->selectmode & SCE_SELECT_FACE` */
1915 BMIter iter;
1916 BMFace *f;
1917 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1919 continue;
1920 }
1921
1922 BMLoop *l_iter, *l_first;
1923 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1924 bool face_select = true;
1925 do {
1926 if (!BM_elem_flag_test(l_iter, BM_ELEM_SELECT_UV) ||
1928 {
1929 face_select = false;
1930 break;
1931 }
1932 } while ((l_iter = l_iter->next) != l_first);
1933 if (face_select) {
1934 BM_face_select_set(bm, f, true);
1935 }
1936 }
1937 }
1938
1940
1942}
1943
1945
1946/* -------------------------------------------------------------------- */
1974
1975/* Asserting can be useful to inspect the values while debugging. */
1976#if 0 /* Useful when debugging. */
1977# define MAYBE_ASSERT BLI_assert(0)
1978#elif 0 /* Can also be useful. */
1979# define MAYBE_ASSERT printf(AT "\n")
1980#else
1981# define MAYBE_ASSERT
1982#endif
1983
1984#define INCF_MAYBE_ASSERT(var) \
1985 { \
1986 MAYBE_ASSERT; \
1987 (var) += 1; \
1988 } \
1989 ((void)0)
1990
1992{
1993 BMIter fiter;
1994 BMFace *f;
1995 BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
1996 BMLoop *l_iter, *l_first;
1997 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1998 do {
2000 } while ((l_iter = l_iter->next) != l_first);
2001 }
2002}
2003
2010{
2011 bool is_valid = true;
2012
2013 /* Vertices. */
2014 {
2015 int &error_count = info_sub.count_uv_vert_any_selected_with_vert_unselected;
2016 BLI_assert(error_count == 0);
2017 BMIter fiter;
2018 BMFace *f;
2019 BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
2021 continue;
2022 }
2023
2024 BMLoop *l_iter, *l_first;
2025 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
2026 do {
2027 if (BM_elem_flag_test(l_iter, BM_ELEM_SELECT_UV)) {
2028 if (!BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
2029 INCF_MAYBE_ASSERT(error_count);
2030 }
2031 }
2032 } while ((l_iter = l_iter->next) != l_first);
2033 }
2034 if (error_count) {
2035 is_valid = false;
2036 }
2037 }
2038
2039 {
2040 int &error_count = info_sub.count_uv_vert_none_selected_with_vert_selected;
2041 BLI_assert(error_count == 0);
2042 BMIter viter;
2043 BMIter liter;
2044
2045 BMVert *v;
2046 BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
2048 continue;
2049 }
2051 continue;
2052 }
2053
2054 bool any_loop_selected = false;
2055 {
2056 BMLoop *l;
2057 BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
2059 any_loop_selected = true;
2060 break;
2061 }
2062 }
2063 }
2064
2065 if (any_loop_selected == false) {
2066 INCF_MAYBE_ASSERT(error_count);
2067 }
2068 }
2069 if (error_count) {
2070 is_valid = false;
2071 }
2072 }
2073
2074 /* Edges. */
2075 {
2076 int &error_count = info_sub.count_uv_edge_any_selected_with_edge_unselected;
2077 BLI_assert(error_count == 0);
2078 BMIter fiter;
2079 BMFace *f;
2080 BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
2082 continue;
2083 }
2084
2085 BMLoop *l_iter, *l_first;
2086 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
2087 do {
2089 if (!BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
2090 INCF_MAYBE_ASSERT(error_count);
2091 }
2092 }
2093 } while ((l_iter = l_iter->next) != l_first);
2094 }
2095 if (error_count) {
2096 is_valid = false;
2097 }
2098 }
2099
2100 /* When vertex selection is enabled, it's possible for UV's
2101 * that don't form a selected UV edge to form a selected viewport edge.
2102 * So, it only makes sense to perform this check in edge selection mode. */
2103 if ((bm->selectmode & SCE_SELECT_VERTEX) == 0) {
2104 int &error_count = info_sub.count_uv_edge_none_selected_with_edge_selected;
2105 BLI_assert(error_count == 0);
2106 BMIter eiter;
2107
2108 BMEdge *e;
2109 BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
2111 continue;
2112 }
2114 continue;
2115 }
2116 if (e->l == nullptr) {
2117 continue;
2118 }
2119 bool any_loop_selected = false;
2120 BMLoop *l_iter = e->l;
2121 do {
2122 if (BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
2123 continue;
2124 }
2126 any_loop_selected = true;
2127 break;
2128 }
2129 } while ((l_iter = l_iter->radial_next) != e->l);
2130 if (any_loop_selected == false) {
2131 INCF_MAYBE_ASSERT(error_count);
2132 }
2133 }
2134 if (error_count) {
2135 is_valid = false;
2136 }
2137 }
2138
2139 return is_valid;
2140}
2141
2143{
2144 bool is_valid = true;
2145
2146 /* Vertices are flushed to edges. */
2147 {
2148 int &error_count_selected = info_sub.count_uv_edge_selected_with_any_verts_unselected;
2149 int &error_count_unselected = info_sub.count_uv_edge_unselected_with_all_verts_selected;
2150 BLI_assert(error_count_selected == 0 && error_count_unselected == 0);
2151 BMIter fiter;
2152 BMFace *f;
2153 BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
2155 continue;
2156 }
2157 BMLoop *l_iter, *l_first;
2158 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
2159 do {
2160 const bool v_curr_select = BM_elem_flag_test(l_iter, BM_ELEM_SELECT_UV);
2161 const bool v_next_select = BM_elem_flag_test(l_iter->next, BM_ELEM_SELECT_UV);
2163 if (!v_curr_select || !v_next_select) {
2164 INCF_MAYBE_ASSERT(error_count_selected);
2165 }
2166 }
2167 else {
2168 if (v_curr_select && v_next_select) {
2169 /* Only an error in with vertex selection mode. */
2170 if (bm->selectmode & SCE_SELECT_VERTEX) {
2171 INCF_MAYBE_ASSERT(error_count_unselected);
2172 }
2173 }
2174 }
2175 } while ((l_iter = l_iter->next) != l_first);
2176 }
2177 if (error_count_selected || error_count_unselected) {
2178 is_valid = false;
2179 }
2180 }
2181
2182 /* Vertices & edges are flushed to faces. */
2183 {
2184 int &error_count_verts_selected = info_sub.count_uv_face_selected_with_any_verts_unselected;
2185 int &error_count_verts_unselected = info_sub.count_uv_face_unselected_with_all_verts_selected;
2186
2187 int &error_count_edges_selected = info_sub.count_uv_face_selected_with_any_edges_unselected;
2188 int &error_count_edges_unselected = info_sub.count_uv_face_unselected_with_all_edges_selected;
2189
2190 BLI_assert(error_count_verts_selected == 0 && error_count_verts_unselected == 0);
2191 BLI_assert(error_count_edges_selected == 0 && error_count_edges_unselected == 0);
2192 BMIter fiter;
2193 BMFace *f;
2194 BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
2196 continue;
2197 }
2198 int uv_vert_select = 0;
2199 int uv_edge_select = 0;
2200 BMLoop *l_iter, *l_first;
2201 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
2202 do {
2203 if (BM_elem_flag_test(l_iter, BM_ELEM_SELECT_UV)) {
2204 uv_vert_select += 1;
2205 }
2206
2208 uv_edge_select += 1;
2209 }
2210 } while ((l_iter = l_iter->next) != l_first);
2211
2213 if (uv_vert_select != f->len) {
2214 INCF_MAYBE_ASSERT(error_count_verts_selected);
2215 }
2216 if (uv_edge_select != f->len) {
2217 INCF_MAYBE_ASSERT(error_count_edges_selected);
2218 }
2219 }
2220 else {
2221 /* Only an error with vertex or edge selection modes. */
2222 if (bm->selectmode & SCE_SELECT_VERTEX) {
2223 if (uv_vert_select == f->len) {
2224 INCF_MAYBE_ASSERT(error_count_verts_unselected);
2225 }
2226 }
2227 else if (bm->selectmode & SCE_SELECT_EDGE) {
2228 if (uv_edge_select == f->len) {
2229 INCF_MAYBE_ASSERT(error_count_edges_unselected);
2230 }
2231 }
2232 }
2233 }
2234
2235 if (error_count_verts_selected || error_count_verts_unselected) {
2236 is_valid = false;
2237 }
2238 if (error_count_edges_selected || error_count_edges_unselected) {
2239 is_valid = false;
2240 }
2241 }
2242
2243 return is_valid;
2244}
2245
2247 const int cd_loop_uv_offset,
2249{
2250 bool is_valid = true;
2251 enum {
2252 UV_IS_SELECTED = 1 << 0,
2253 UV_IS_UNSELECTED = 1 << 1,
2254 };
2255
2256 BLI_assert(cd_loop_uv_offset != -1);
2257
2258 /* Handle vertices. */
2259 {
2260 int &error_count = info_sub.count_uv_vert_non_contiguous_selected;
2261 BLI_assert(error_count == 0);
2262
2264
2265 auto loop_vert_select_test_fn = [&cd_loop_uv_offset](BMLoop *l_base) -> int {
2266 BMIter liter;
2267 BMLoop *l_other;
2268
2270
2271 int select_test = 0;
2272
2273 BM_ITER_ELEM (l_other, &liter, l_base->v, BM_LOOPS_OF_VERT) {
2274 /* Ignore all hidden. */
2275 if (BM_elem_flag_test(l_other->f, BM_ELEM_HIDDEN)) {
2276 continue;
2277 }
2278 if (BM_elem_flag_test(l_other, BM_ELEM_TAG)) {
2279 continue;
2280 }
2281 if (!BM_loop_uv_share_vert_check(l_base, l_other, cd_loop_uv_offset)) {
2282 continue;
2283 }
2284 select_test |= BM_elem_flag_test(l_other, BM_ELEM_SELECT_UV) ? UV_IS_SELECTED :
2285 UV_IS_UNSELECTED;
2286 if (select_test == (UV_IS_SELECTED | UV_IS_UNSELECTED)) {
2287 break;
2288 }
2289 }
2290 return select_test;
2291 };
2292 BMIter fiter;
2293 BMFace *f;
2294 BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
2296 continue;
2297 }
2298 BMLoop *l_iter, *l_first;
2299 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
2300 do {
2301 if (BM_elem_flag_test(l_iter, BM_ELEM_TAG)) {
2302 continue;
2303 }
2304 if (loop_vert_select_test_fn(l_iter) == (UV_IS_SELECTED | UV_IS_UNSELECTED)) {
2305 INCF_MAYBE_ASSERT(error_count);
2306 }
2307 } while ((l_iter = l_iter->next) != l_first);
2308 }
2309 if (error_count) {
2310 is_valid = false;
2311 }
2312 }
2313
2314 /* Handle edges. */
2315 {
2316 int &error_count = info_sub.count_uv_edge_non_contiguous_selected;
2317 BLI_assert(error_count == 0);
2319
2320 auto loop_edge_select_test_fn = [&cd_loop_uv_offset](BMLoop *l_base) -> int {
2322
2323 int select_test = 0;
2324 if (l_base->radial_next != l_base) {
2325 BMLoop *l_other = l_base->radial_next;
2326 do {
2327 /* Ignore all hidden. */
2328 if (BM_elem_flag_test(l_other->f, BM_ELEM_HIDDEN)) {
2329 continue;
2330 }
2331 if (BM_elem_flag_test(l_other, BM_ELEM_TAG)) {
2332 continue;
2333 }
2334 if (!BM_loop_uv_share_edge_check(l_base, l_other, cd_loop_uv_offset)) {
2335 continue;
2336 }
2337
2338 select_test |= BM_elem_flag_test(l_other, BM_ELEM_SELECT_UV_EDGE) ? UV_IS_SELECTED :
2339 UV_IS_UNSELECTED;
2340 if (select_test == (UV_IS_SELECTED | UV_IS_UNSELECTED)) {
2341 break;
2342 }
2343 } while ((l_other = l_other->radial_next) != l_base);
2344 }
2345 return select_test;
2346 };
2347 BMIter fiter;
2348 BMFace *f;
2349 BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
2351 continue;
2352 }
2353 BMLoop *l_iter, *l_first;
2354 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
2355 do {
2356 if (BM_elem_flag_test(l_iter, BM_ELEM_TAG)) {
2357 continue;
2358 }
2359 if (loop_edge_select_test_fn(l_iter) == (UV_IS_SELECTED | UV_IS_UNSELECTED)) {
2360 INCF_MAYBE_ASSERT(error_count);
2361 }
2362 } while ((l_iter = l_iter->next) != l_first);
2363 }
2364 if (error_count) {
2365 is_valid = false;
2366 }
2367 }
2368 return is_valid;
2369}
2370
2375 BMesh *bm, const int cd_loop_uv_offset, UVSelectValidateInfo_FlushAndContiguous &info_sub)
2376{
2377 bool is_valid = true;
2378
2379 /* Check isolated selection. */
2380 if ((bm->selectmode & SCE_SELECT_EDGE) && (bm->selectmode & SCE_SELECT_VERTEX) == 0) {
2381 int &error_count = info_sub.count_uv_vert_isolated_in_edge_or_face_mode;
2382 BLI_assert(error_count == 0);
2383
2384 if (bm->selectmode & SCE_SELECT_EDGE) {
2385 /* All selected UV's must have at least one selected edge. */
2386 BMIter fiter;
2387 BMFace *f;
2388 BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
2390 continue;
2391 }
2392 BMLoop *l_iter, *l_first;
2393 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
2394 do {
2395 /* Only check selected vertices. */
2396 if (BM_elem_flag_test(l_iter, BM_ELEM_SELECT_UV)) {
2400 l_iter, BM_ELEM_SELECT_UV_EDGE, cd_loop_uv_offset))
2401 {
2402 INCF_MAYBE_ASSERT(error_count);
2403 }
2404 }
2405 } while ((l_iter = l_iter->next) != l_first);
2406 }
2407 }
2408 if (error_count) {
2409 is_valid = false;
2410 }
2411 }
2412
2413 if ((bm->selectmode & SCE_SELECT_FACE) &&
2414 (bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0)
2415 {
2416 int &error_count_vert = info_sub.count_uv_vert_isolated_in_face_mode;
2417 int &error_count_edge = info_sub.count_uv_edge_isolated_in_face_mode;
2418 BLI_assert(error_count_vert == 0 && error_count_edge == 0);
2419
2420 /* All selected UV's must have at least one selected edge. */
2421 BMIter fiter;
2422 BMFace *f;
2423 BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
2425 continue;
2426 }
2427 /* If this face is selected, there is no need to search over it's verts. */
2429 continue;
2430 }
2431 BMLoop *l_iter, *l_first;
2432 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
2433 do {
2434 /* Only check selected vertices. */
2435 if (BM_elem_flag_test(l_iter, BM_ELEM_SELECT_UV)) {
2437 l_iter, BM_ELEM_SELECT_UV, cd_loop_uv_offset))
2438 {
2439 INCF_MAYBE_ASSERT(error_count_vert);
2440 }
2441 }
2442 /* Only check selected edges. */
2445 l_iter, BM_ELEM_SELECT_UV, cd_loop_uv_offset))
2446 {
2447 INCF_MAYBE_ASSERT(error_count_edge);
2448 }
2449 }
2450 } while ((l_iter = l_iter->next) != l_first);
2451 }
2452
2453 if (error_count_vert || error_count_edge) {
2454 is_valid = false;
2455 }
2456 }
2457 return is_valid;
2458}
2459
2460#undef INCF_MAYBE_ASSERT
2461#undef MAYBE_ASSERT
2462
2464 const int cd_loop_uv_offset,
2465 const bool check_sync,
2466 const bool check_flush,
2467 const bool check_contiguous,
2468 UVSelectValidateInfo *info_p)
2469{
2470 /* Correctness is as follows:
2471 *
2472 * - UV selection must match the viewport selection.
2473 * - If a vertex is selected at least one if it's UV verts must be selected.
2474 * - If an edge is selected at least one of it's UV verts must be selected.
2475 *
2476 * - UV selection must be flushed.
2477 *
2478 * Notes:
2479 * - When all vertices of a face are selected in the viewport
2480 * (and therefor the face) is selected, it's possible the UV face is *not* selected,
2481 * because the vertices in the viewport may be selected because of other selected UV's,
2482 * not part of the UV's associated with the face.
2483 *
2484 * Therefor it is possible for a viewport face to be selected
2485 * with an unselected UV face.
2486 */
2487
2488 UVSelectValidateInfo _info_fallback = {};
2489 UVSelectValidateInfo &info = info_p ? *info_p : _info_fallback;
2490
2491 bool is_valid = true;
2492 if (check_sync) {
2493 BLI_assert(bm->uv_select_sync_valid);
2495 is_valid = false;
2496 }
2497 }
2498
2499 if (check_flush) {
2501 is_valid = false;
2502 }
2503 }
2504
2505 if (check_contiguous) {
2506 if (!bm_mesh_uvselect_check_contiguous(bm, cd_loop_uv_offset, info.contiguous)) {
2507 is_valid = false;
2508 }
2509 }
2510
2511 if (check_flush && check_contiguous) {
2513 {
2514 is_valid = false;
2515 }
2516 }
2517 return is_valid;
2518}
2519
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
MINLINE unsigned short highest_order_bit_s(unsigned short n)
#define UNUSED_VARS_NDEBUG(...)
#define ELEM(...)
@ SCE_SELECT_FACE
@ SCE_SELECT_VERTEX
@ SCE_SELECT_EDGE
Read Guarded memory(de)allocation.
#define BM_ELEM_SELECT_UV_EDGE
#define BM_FACE_FIRST_LOOP(p)
@ BM_ELEM_HIDDEN
@ BM_ELEM_SELECT
@ BM_ELEM_SELECT_UV
@ BM_ELEM_TAG
#define BM_elem_flag_disable(ele, hflag)
#define BM_elem_flag_set(ele, hflag, val)
#define BM_elem_flag_test(ele, hflag)
#define BM_elem_flag_test_bool(ele, hflag)
#define BM_elem_flag_enable(ele, hflag)
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_VERT
BMesh * bm
void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
Select Face.
void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
Select Vert.
void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
Select Edge.
void BM_select_history_validate(BMesh *bm)
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
void BM_face_select_set_noflush(BMesh *bm, BMFace *f, const bool select)
void BM_mesh_select_flush_from_verts(BMesh *bm, const bool select)
#define BM_SELECT_HISTORY_BACKUP(bm)
#define BM_SELECT_HISTORY_RESTORE(bm)
#define BM_FACE
#define BM_EDGE
#define BM_VERT
bool BM_edge_is_any_face_flag_test(const BMEdge *e, const char hflag)
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
bool BM_loop_uv_share_edge_check(const BMLoop *l_a, const BMLoop *l_b, const int cd_loop_uv_offset)
bool BM_loop_uv_share_vert_check(const BMLoop *l_a, const BMLoop *l_b, const int cd_loop_uv_offset)
BLI_INLINE BMEdge * bmesh_disk_edge_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
bool BM_loop_edge_uvselect_check_other_face(BMLoop *l, const char hflag, const int cd_loop_uv_offset)
static void bm_mesh_uvselect_flush_from_mesh_sticky_vert_for_vert_mode(BMesh *bm)
void BM_mesh_uvselect_flush_from_faces_only_select(BMesh *bm)
static void bm_mesh_uvselect_flush_from_mesh_sticky_vert_for_edge_mode(BMesh *bm)
bool BM_loop_edge_uvselect_check_other_loop_edge(BMLoop *l, const char hflag, const int cd_loop_uv_offset)
void BM_face_uvselect_set_pick(BMesh *bm, BMFace *f, bool select, const BMUVSelectPickParams &params)
bool BM_face_uvselect_check_edges_all(BMFace *f)
void BM_mesh_uvselect_sync_from_mesh_sticky_vert(BMesh *bm)
void BM_mesh_uvselect_flush_from_loop_edges_only_select(BMesh *bm)
static void bm_mesh_uvselect_mode_flush_down_deselect_only(BMesh *bm, const short select_mode, const int cd_loop_uv_offset, const bool shared, const bool check_verts, const bool check_edges)
void BM_mesh_uvselect_mode_flush(BMesh *bm)
void BM_face_uvselect_set_shared(BMesh *bm, BMFace *f, bool select, const int cd_loop_uv_offset)
static void bm_edge_uvselect_set_pick(BMesh *bm, BMEdge *e, const bool select, const BMUVSelectPickParams &uv_pick_params, const bool caller_handles_face_mode)
void BM_face_uvselect_set_noflush(BMesh *bm, BMFace *f, bool select)
void BM_face_uvselect_set(BMesh *bm, BMFace *f, bool select)
void BM_mesh_uvselect_mode_flush_update(BMesh *bm, const short selectmode_old, const short selectmode_new, const int cd_loop_uv_offset)
void BM_mesh_uvselect_sync_from_mesh_sticky_disabled(BMesh *bm)
static void bm_mesh_uvselect_flush_from_mesh_sticky_location_for_face_mode(BMesh *bm, const int cd_loop_uv_offset)
static void bm_mesh_uvselect_disable_all(BMesh *bm)
static void bm_mesh_loop_clear_tag(BMesh *bm)
static void bm_mesh_uvselect_flush_from_mesh_sticky_vert_for_face_mode(BMesh *bm)
void BM_mesh_uvselect_sync_to_mesh(BMesh *bm)
#define INCF_MAYBE_ASSERT(var)
void BM_mesh_uvselect_flush_shared_only_deselect(BMesh *bm, const int cd_loop_uv_offset)
void BM_mesh_uvselect_flush_shared_only_select(BMesh *bm, const int cd_loop_uv_offset)
static void bm_mesh_uvselect_flush_from_mesh_sticky_location_for_edge_mode(BMesh *bm, const int cd_loop_uv_offset)
bool BM_loop_vert_uvselect_check_other_loop_vert(BMLoop *l, const char hflag, const int cd_loop_uv_offset)
void BM_mesh_uvselect_mode_flush_ex(BMesh *bm, const short selectmode, const bool flush_down)
void BM_mesh_uvselect_flush_from_verts(BMesh *bm, const bool select)
bool BM_loop_edge_uvselect_test(const BMLoop *l)
static void bm_mesh_uvselect_flush_from_mesh_sticky_location_for_vert_mode(BMesh *bm, const int)
bool BM_mesh_uvselect_is_valid(BMesh *bm, const int cd_loop_uv_offset, const bool check_sync, const bool check_flush, const bool check_contiguous, UVSelectValidateInfo *info_p)
void BM_loop_edge_uvselect_set_noflush(BMesh *bm, BMLoop *l, bool select)
static bool bm_mesh_uvselect_check_contiguous(BMesh *bm, const int cd_loop_uv_offset, UVSelectValidateInfo_Contiguous &info_sub)
bool BM_face_uvselect_test(const BMFace *f)
void BM_mesh_uvselect_set_elem_shared(BMesh *bm, bool select, const int cd_loop_uv_offset, const blender::Span< BMLoop * > loop_verts, const blender::Span< BMLoop * > loop_edges, const blender::Span< BMFace * > faces)
void BM_mesh_uvselect_flush_from_faces_only_deselect(BMesh *bm)
static void bm_vert_uvselect_set_pick(BMesh *bm, BMVert *v, const bool select, const BMUVSelectPickParams &, bool caller_handles_edge_or_face_mode)
void BM_mesh_uvselect_flush_from_loop_verts_only_select(BMesh *bm)
bool BM_mesh_uvselect_clear(BMesh *bm)
void BM_mesh_uvselect_flush_post_subdivide(BMesh *bm, const int cd_loop_uv_offset)
void BM_mesh_uvselect_flush_from_loop_edges_only_deselect(BMesh *bm)
bool BM_loop_vert_uvselect_check_other_edge(BMLoop *l, const char hflag, const int cd_loop_uv_offset)
bool BM_loop_vert_uvselect_check_other_loop_edge(BMLoop *l, const char hflag, const int cd_loop_uv_offset)
void BM_mesh_uvselect_flush_from_loop_verts(BMesh *bm)
void BM_mesh_uvselect_flush_from_loop_verts_only_deselect(BMesh *bm)
bool BM_loop_vert_uvselect_test(const BMLoop *l)
void BM_loop_edge_uvselect_set(BMesh *bm, BMLoop *l, bool select)
void BM_mesh_uvselect_sync_from_mesh_sticky_location(BMesh *bm, const int cd_loop_uv_offset)
static bool bm_mesh_uvselect_check_viewport_sync(BMesh *bm, UVSelectValidateInfo_Sync &info_sub)
void BM_mesh_uvselect_flush_from_loop_edges(BMesh *bm, bool flush_down)
static bool bm_mesh_uvselect_check_flush(BMesh *bm, UVSelectValidateInfo_Flush &info_sub)
void BM_mesh_uvselect_set_elem_from_mesh(BMesh *bm, const bool select, const BMUVSelectPickParams &params, const blender::VectorList< BMVert * > &verts, const blender::VectorList< BMEdge * > &edges, const blender::VectorList< BMFace * > &faces)
void BM_edge_uvselect_set_pick(BMesh *bm, BMEdge *e, bool select, const BMUVSelectPickParams &params)
void BM_loop_vert_uvselect_set_noflush(BMesh *bm, BMLoop *l, bool select)
static bool bm_mesh_uvselect_check_flush_and_contiguous(BMesh *bm, const int cd_loop_uv_offset, UVSelectValidateInfo_FlushAndContiguous &info_sub)
static void bm_face_uvselect_set_pick(BMesh *bm, BMFace *f, const bool select, const BMUVSelectPickParams &uv_pick_params)
void BM_mesh_uvselect_flush_from_faces(BMesh *bm, bool flush_down)
void BM_loop_vert_uvselect_set_shared(BMesh *bm, BMLoop *l, bool select, const int cd_loop_uv_offset)
void BM_vert_uvselect_set_pick(BMesh *bm, BMVert *v, bool select, const BMUVSelectPickParams &params)
void BM_loop_edge_uvselect_set_shared(BMesh *bm, BMLoop *l, bool select, const int cd_loop_uv_offset)
void BM_mesh_uvselect_mode_flush_only_select(BMesh *bm)
bool BM_loop_vert_uvselect_check_other_face(BMLoop *l, const char hflag, const int cd_loop_uv_offset)
constexpr bool is_empty() const
Definition BLI_span.hh:260
static float verts[][3]
#define shared
#define select(A, B, C)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
static char faces[256]
struct BMLoop * l
struct BMVert * v
struct BMEdge * e
struct BMLoop * radial_next
struct BMLoop * prev
struct BMFace * f
struct BMLoop * next
UVSelectValidateInfo_Flush flush
UVSelectValidateInfo_FlushAndContiguous flush_contiguous
UVSelectValidateInfo_Sync sync
UVSelectValidateInfo_Contiguous contiguous