Blender V5.0
bmesh_marking.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
15
16#include <cstddef>
17
18#include "MEM_guardedalloc.h"
19
20#include "DNA_scene_types.h"
21
22#include "BLI_listbase.h"
23#include "BLI_math_vector.h"
24#include "BLI_task.h"
25
26#include "bmesh.hh"
27#include "bmesh_query_uv.hh"
28#include "bmesh_structure.hh"
29
30/* For '_FLAG_OVERLAP'. */
31#include "bmesh_private.hh"
32
33/* -------------------------------------------------------------------- */
36
40
41static void recount_totsels_range_vert_func(void * /*userdata*/,
42 MempoolIterData *iter,
43 const TaskParallelTLS *__restrict tls)
44{
45 SelectionCountChunkData *count = static_cast<SelectionCountChunkData *>(tls->userdata_chunk);
46 const BMVert *eve = (const BMVert *)iter;
48 count->selection_len += 1;
49 }
50}
51
52static void recount_totsels_range_edge_func(void * /*userdata*/,
53 MempoolIterData *iter,
54 const TaskParallelTLS *__restrict tls)
55{
56 SelectionCountChunkData *count = static_cast<SelectionCountChunkData *>(tls->userdata_chunk);
57 const BMEdge *eed = (const BMEdge *)iter;
59 count->selection_len += 1;
60 }
61}
62
63static void recount_totsels_range_face_func(void * /*userdata*/,
64 MempoolIterData *iter,
65 const TaskParallelTLS *__restrict tls)
66{
67 SelectionCountChunkData *count = static_cast<SelectionCountChunkData *>(tls->userdata_chunk);
68 const BMFace *efa = (const BMFace *)iter;
70 count->selection_len += 1;
71 }
72}
73
74static void recount_totsels_reduce(const void *__restrict /*userdata*/,
75 void *__restrict chunk_join,
76 void *__restrict chunk)
77{
78 SelectionCountChunkData *dst = static_cast<SelectionCountChunkData *>(chunk_join);
79 const SelectionCountChunkData *src = static_cast<const SelectionCountChunkData *>(chunk);
80 dst->selection_len += src->selection_len;
81}
82
84{
86
87 TaskParallelMempoolFunc range_func = nullptr;
88 if (iter_type == BM_VERTS_OF_MESH) {
90 }
91 else if (iter_type == BM_EDGES_OF_MESH) {
93 }
94 else if (iter_type == BM_FACES_OF_MESH) {
96 }
97 return range_func;
98}
99
100static int recount_totsel(BMesh *bm, BMIterType iter_type)
101{
102 const int MIN_ITER_SIZE = 1024;
103
104 TaskParallelSettings settings;
107 settings.min_iter_per_thread = MIN_ITER_SIZE;
108
110 settings.userdata_chunk = &count;
111 settings.userdata_chunk_size = sizeof(count);
112
114 BM_iter_parallel(bm, iter_type, range_func, nullptr, &settings);
115 return count.selection_len;
116}
117
119{
120 bm->totvertsel = recount_totsel(bm, BM_VERTS_OF_MESH);
121}
122
124{
125 bm->totedgesel = recount_totsel(bm, BM_EDGES_OF_MESH);
126}
127
129{
130 bm->totfacesel = recount_totsel(bm, BM_FACES_OF_MESH);
131}
132
139
140#ifndef NDEBUG
142{
143 return bm->totvertsel == recount_totsel(bm, BM_VERTS_OF_MESH) &&
144 bm->totedgesel == recount_totsel(bm, BM_EDGES_OF_MESH) &&
145 bm->totfacesel == recount_totsel(bm, BM_FACES_OF_MESH);
146}
147#endif
148
150
151/* -------------------------------------------------------------------- */
154
155static bool bm_vert_is_edge_select_any_other(const BMVert *v, const BMEdge *e_first)
156{
157 const BMEdge *e_iter = e_first;
158
159 /* start by stepping over the current edge */
160 while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first) {
161 if (BM_elem_flag_test(e_iter, BM_ELEM_SELECT)) {
162 return true;
163 }
164 }
165 return false;
166}
167
168#if 0
169static bool bm_vert_is_edge_select_any(const BMVert *v)
170{
171 if (v->e) {
172 const BMEdge *e_iter, *e_first;
173 e_iter = e_first = v->e;
174 do {
175 if (BM_elem_flag_test(e_iter, BM_ELEM_SELECT)) {
176 return true;
177 }
178 } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
179 }
180 return false;
181}
182#endif
183
185{
186 if (v->e) {
187 const BMEdge *e_iter, *e_first;
188 e_iter = e_first = v->e;
189 do {
190 if (!BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN)) {
191 return true;
192 }
193 } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
194 }
195 return false;
196}
197
199{
200 const BMLoop *l_iter = l_first;
201
202 /* start by stepping over the current face */
203 while ((l_iter = l_iter->radial_next) != l_first) {
204 if (BM_elem_flag_test(l_iter->f, BM_ELEM_SELECT)) {
205 return true;
206 }
207 }
208 return false;
209}
210
211#if 0
212static bool bm_edge_is_face_select_any(const BMEdge *e)
213{
214 if (e->l) {
215 const BMLoop *l_iter, *l_first;
216 l_iter = l_first = e->l;
217 do {
218 if (BM_elem_flag_test(l_iter->f, BM_ELEM_SELECT)) {
219 return true;
220 }
221 } while ((l_iter = l_iter->radial_next) != l_first);
222 }
223 return false;
224}
225#endif
226
228{
229 if (e->l) {
230 const BMLoop *l_iter, *l_first;
231 l_iter = l_first = e->l;
232 do {
233 if (!BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
234 return true;
235 }
236 } while ((l_iter = l_iter->radial_next) != l_first);
237 }
238 return false;
239}
240
242
244{
245 if (bm->selectmode & SCE_SELECT_VERTEX) {
246 return !ELEM(bm->totvertsel, 0, bm->totvert);
247 }
248 if (bm->selectmode & SCE_SELECT_EDGE) {
249 return !ELEM(bm->totedgesel, 0, bm->totedge);
250 }
251 return !ELEM(bm->totfacesel, 0, bm->totface);
252}
253
254void BM_mesh_select_mode_clean_ex(BMesh *bm, const short selectmode)
255{
256 if (selectmode & SCE_SELECT_VERTEX) {
257 /* pass */
258 }
259 else if (selectmode & SCE_SELECT_EDGE) {
260 BMIter iter;
261
262 if (bm->totvertsel) {
263 BMVert *v;
264 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
266 }
267 bm->totvertsel = 0;
268 }
269
270 if (bm->totedgesel) {
271 BMEdge *e;
272 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
274 BM_vert_select_set(bm, e->v1, true);
275 BM_vert_select_set(bm, e->v2, true);
276 }
277 }
278 }
279 }
280 else if (selectmode & SCE_SELECT_FACE) {
281 BMIter iter;
282
283 if (bm->totvertsel) {
284 BMVert *v;
285 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
287 }
288 bm->totvertsel = 0;
289 }
290
291 if (bm->totedgesel) {
292 BMEdge *e;
293 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
295 }
296 bm->totedgesel = 0;
297 }
298
299 if (bm->totfacesel) {
300 BMFace *f;
301 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
303 BMLoop *l_iter, *l_first;
304 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
305 do {
306 BM_edge_select_set(bm, l_iter->e, true);
307 } while ((l_iter = l_iter->next) != l_first);
308 }
309 }
310 }
311 }
312}
313
318
319/* -------------------------------------------------------------------- */
322
326
328 MempoolIterData *iter,
329 const TaskParallelTLS *__restrict tls)
330{
331 SelectionFlushChunkData *chunk_data = static_cast<SelectionFlushChunkData *>(
332 tls->userdata_chunk);
333 BMEdge *e = (BMEdge *)iter;
334 const bool is_selected = BM_elem_flag_test(e, BM_ELEM_SELECT);
335 const bool is_hidden = BM_elem_flag_test(e, BM_ELEM_HIDDEN);
336 if (!is_hidden &&
338 {
340 chunk_data->delta_selection_len += is_selected ? 0 : 1;
341 }
342 else {
344 chunk_data->delta_selection_len += is_selected ? -1 : 0;
345 }
346}
347
349 MempoolIterData *iter,
350 const TaskParallelTLS *__restrict tls)
351{
352 SelectionFlushChunkData *chunk_data = static_cast<SelectionFlushChunkData *>(
353 tls->userdata_chunk);
354 BMFace *f = (BMFace *)iter;
355 BMLoop *l_iter;
356 BMLoop *l_first;
357 const bool is_selected = BM_elem_flag_test(f, BM_ELEM_SELECT);
358 bool ok = true;
360 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
361 do {
362 if (!BM_elem_flag_test(l_iter->e, BM_ELEM_SELECT)) {
363 ok = false;
364 break;
365 }
366 } while ((l_iter = l_iter->next) != l_first);
367 }
368 else {
369 ok = false;
370 }
371
373 if (is_selected && !ok) {
374 chunk_data->delta_selection_len -= 1;
375 }
376 else if (ok && !is_selected) {
377 chunk_data->delta_selection_len += 1;
378 }
379}
380
381static void bm_mesh_select_mode_flush_reduce_fn(const void *__restrict /*userdata*/,
382 void *__restrict chunk_join,
383 void *__restrict chunk)
384{
385 SelectionFlushChunkData *dst = static_cast<SelectionFlushChunkData *>(chunk_join);
386 const SelectionFlushChunkData *src = static_cast<const SelectionFlushChunkData *>(chunk);
388}
389
391{
392 SelectionFlushChunkData chunk_data = {0};
393
394 TaskParallelSettings settings;
396 settings.use_threading = bm->totedge >= BM_THREAD_LIMIT;
397 settings.userdata_chunk = &chunk_data;
398 settings.userdata_chunk_size = sizeof(chunk_data);
400
401 BM_iter_parallel(
403 bm->totedgesel += chunk_data.delta_selection_len;
404}
405
407{
408 SelectionFlushChunkData chunk_data = {0};
409
410 TaskParallelSettings settings;
412 settings.use_threading = bm->totface >= BM_THREAD_LIMIT;
413 settings.userdata_chunk = &chunk_data;
414 settings.userdata_chunk_size = sizeof(chunk_data);
416
417 BM_iter_parallel(
419 bm->totfacesel += chunk_data.delta_selection_len;
420}
421
428{
429 BMIter iter;
430 BMEdge *e;
431 bool any_select = false;
432 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
434 continue;
435 }
437 any_select = true;
438 }
439 else {
440 BM_vert_select_set(bm, e->v1, false);
441 BM_vert_select_set(bm, e->v2, false);
442 }
443 }
444 if (any_select) {
445 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
447 continue;
448 }
450 BM_vert_select_set(bm, e->v1, true);
451 BM_vert_select_set(bm, e->v2, true);
452 }
453 }
454 }
455}
456
463{
464 BMIter iter;
465 BMFace *f;
466 bool any_select = false;
467 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
469 continue;
470 }
472 any_select = true;
473 }
474 else {
475 BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
476 BMLoop *l_iter = l_first;
477 do {
478 BM_vert_select_set(bm, l_iter->v, false);
479 BM_edge_select_set_noflush(bm, l_iter->e, false);
480 } while ((l_iter = l_iter->next) != l_first);
481 }
482 }
483 if (any_select) {
484 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
486 continue;
487 }
489 BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
490 BMLoop *l_iter = l_first;
491 do {
492 BM_vert_select_set(bm, l_iter->v, true);
493 BM_edge_select_set_noflush(bm, l_iter->e, true);
494 } while ((l_iter = l_iter->next) != l_first);
495 }
496 }
497 }
498}
499
501{
502 const bool flush_down = bool(flag & BMSelectFlushFlag::Down);
503 if (flush_down) {
504 if (selectmode & SCE_SELECT_VERTEX) {
505 /* Pass. */
506 }
507 else if (selectmode & SCE_SELECT_EDGE) {
509 }
510 else if (selectmode & SCE_SELECT_FACE) {
512 }
513 }
514
515 /* Always flush up. */
516 {
517 if (selectmode & SCE_SELECT_VERTEX) {
519 }
520
521 if (selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) {
523 }
524 }
525
526 /* Remove any deselected elements from the BMEditSelection */
528
531 }
534 }
537 }
539}
540
545
547
549{
550 if (select) {
551 BMEdge *e;
552 BMLoop *l_iter;
553 BMLoop *l_first;
554 BMFace *f;
555
556 BMIter eiter;
557 BMIter fiter;
558
559 bool ok;
560
561 BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
564 {
566 }
567 }
568 BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
569 ok = true;
571 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
572 do {
573 if (!BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
574 ok = false;
575 break;
576 }
577 } while ((l_iter = l_iter->next) != l_first);
578 }
579 else {
580 ok = false;
581 }
582
583 if (ok) {
585 }
586 }
587 }
588 else {
589 BMIter eiter;
590 BMEdge *e;
591
592 BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
597 {
599 }
600 }
601
602 if (e->l && !BM_elem_flag_test(e, BM_ELEM_SELECT)) {
603 BMLoop *l_iter;
604 BMLoop *l_first;
605
606 l_iter = l_first = e->l;
607 do {
609 } while ((l_iter = l_iter->radial_next) != l_first);
610 }
611 }
612 }
613 /* Remove any deselected elements from the #BMEditSelection. */
615 }
616
618}
619
621{
622 BLI_assert(v->head.htype == BM_VERT);
623
625 return;
626 }
627
628 if (select) {
631 bm->totvertsel += 1;
632 }
633 }
634 else {
636 bm->totvertsel -= 1;
638 }
639 }
640}
641
643{
644 BLI_assert(e->head.htype == BM_EDGE);
645
647 return;
648 }
649
650 if (select) {
653 bm->totedgesel += 1;
654 }
655 BM_vert_select_set(bm, e->v1, true);
656 BM_vert_select_set(bm, e->v2, true);
657 }
658 else {
661 bm->totedgesel -= 1;
662 }
663
664 if ((bm->selectmode & SCE_SELECT_VERTEX) == 0) {
665 int i;
666
667 /* check if the vert is used by a selected edge */
668 for (i = 0; i < 2; i++) {
669 BMVert *v = *((&e->v1) + i);
670 if (bm_vert_is_edge_select_any_other(v, e) == false) {
671 BM_vert_select_set(bm, v, false);
672 }
673 }
674 }
675 else {
676 BM_vert_select_set(bm, e->v1, false);
677 BM_vert_select_set(bm, e->v2, false);
678 }
679 }
680}
681
683{
684 BMLoop *l_iter;
685 BMLoop *l_first;
686
688
690 return;
691 }
692
693 if (select) {
696 bm->totfacesel += 1;
697 }
698
699 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
700 do {
701 BM_vert_select_set(bm, l_iter->v, true);
702 BM_edge_select_set(bm, l_iter->e, true);
703 } while ((l_iter = l_iter->next) != l_first);
704 }
705 else {
706
709 bm->totfacesel -= 1;
710 }
719 if (bm->selectmode & SCE_SELECT_VERTEX) {
720 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
721 do {
722 BM_vert_select_set(bm, l_iter->v, false);
723 BM_edge_select_set_noflush(bm, l_iter->e, false);
724 } while ((l_iter = l_iter->next) != l_first);
725 }
726 else {
731 if (bm->selectmode & SCE_SELECT_EDGE) {
732 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
733 do {
734 BM_edge_select_set_noflush(bm, l_iter->e, false);
735 } while ((l_iter = l_iter->next) != l_first);
736 }
737 else {
738 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
739 do {
740 if (bm_edge_is_face_select_any_other(l_iter) == false) {
741 BM_edge_select_set_noflush(bm, l_iter->e, false);
742 }
743 } while ((l_iter = l_iter->next) != l_first);
744 }
745
746 /* flush down to verts */
747 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
748 do {
749 if (bm_vert_is_edge_select_any_other(l_iter->v, l_iter->e) == false) {
750 BM_vert_select_set(bm, l_iter->v, false);
751 }
752 } while ((l_iter = l_iter->next) != l_first);
753 }
754 }
755}
756
757/* -------------------------------------------------------------------- */
760
762{
763 BLI_assert(e->head.htype == BM_EDGE);
764
766 return;
767 }
768
769 if (select) {
772 bm->totedgesel += 1;
773 }
774 }
775 else {
778 bm->totedgesel -= 1;
779 }
780 }
781}
782
784{
786
788 return;
789 }
790
791 if (select) {
794 bm->totfacesel += 1;
795 }
796 }
797 else {
800 bm->totfacesel -= 1;
801 }
802 }
803}
804
806
807void BM_mesh_select_mode_set(BMesh *bm, int selectmode)
808{
809 BMIter iter;
810 BMElem *ele;
811
812 bm->selectmode = selectmode;
813
814 if (bm->selectmode & SCE_SELECT_VERTEX) {
815/* disabled because selection flushing handles these */
816#if 0
817 BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
819 }
820 BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
822 }
823#endif
825 }
826 else if (bm->selectmode & SCE_SELECT_EDGE) {
827/* disabled because selection flushing handles these */
828#if 0
829 BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
831 }
832#endif
833
834 BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
836 BM_edge_select_set(bm, (BMEdge *)ele, true);
837 }
838 }
840 }
841 else if (bm->selectmode & SCE_SELECT_FACE) {
842/* disabled because selection flushing handles these */
843#if 0
844 BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
846 }
847#endif
848 BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
850 BM_face_select_set(bm, (BMFace *)ele, true);
851 }
852 }
854 }
855}
856
861 const char htype,
862 const char hflag,
863 const bool respecthide,
864 const bool test_for_enabled)
865{
866 BMElem *ele;
867 BMIter iter;
868 int tot = 0;
869
870 BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
871
872 if (htype & BM_VERT) {
873 BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
874 if (respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) {
875 continue;
876 }
877 if (BM_elem_flag_test_bool(ele, hflag) == test_for_enabled) {
878 tot++;
879 }
880 }
881 }
882 if (htype & BM_EDGE) {
883 BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
884 if (respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) {
885 continue;
886 }
887 if (BM_elem_flag_test_bool(ele, hflag) == test_for_enabled) {
888 tot++;
889 }
890 }
891 }
892 if (htype & BM_FACE) {
893 BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
894 if (respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) {
895 continue;
896 }
897 if (BM_elem_flag_test_bool(ele, hflag) == test_for_enabled) {
898 tot++;
899 }
900 }
901 }
902
903 return tot;
904}
905
907 const char htype,
908 const char hflag,
909 const bool respecthide)
910{
911 return bm_mesh_flag_count(bm, htype, hflag, respecthide, true);
912}
913
915 const char htype,
916 const char hflag,
917 const bool respecthide)
918{
919 return bm_mesh_flag_count(bm, htype, hflag, respecthide, false);
920}
921
922void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select)
923{
924 switch (ele->head.htype) {
925 case BM_VERT:
927 break;
928 case BM_EDGE:
930 break;
931 case BM_FACE:
933 break;
934 default:
935 BLI_assert(0);
936 break;
937 }
938}
939
941{
942 bm->act_face = f;
943}
944
945int BM_mesh_active_face_index_get(BMesh *bm, bool is_sloppy, bool is_selected)
946{
947 const BMFace *f = BM_mesh_active_face_get(bm, is_sloppy, is_selected);
948 return f ? BM_elem_index_get(f) : -1;
949}
950
952{
954 return e ? BM_elem_index_get(e) : -1;
955}
956
958{
960 return v ? BM_elem_index_get(v) : -1;
961}
962
963BMFace *BM_mesh_active_face_get(BMesh *bm, const bool is_sloppy, const bool is_selected)
964{
965 if (bm->act_face && (!is_selected || BM_elem_flag_test(bm->act_face, BM_ELEM_SELECT))) {
966 return bm->act_face;
967 }
968 if (is_sloppy) {
969 BMIter iter;
970 BMFace *f = nullptr;
971 BMEditSelection *ese;
972
973 /* Find the latest non-hidden face from the BMEditSelection */
974 ese = static_cast<BMEditSelection *>(bm->selected.last);
975 for (; ese; ese = ese->prev) {
976 if (ese->htype == BM_FACE) {
977 f = (BMFace *)ese->ele;
978
980 f = nullptr;
981 }
982 else if (is_selected && !BM_elem_flag_test(f, BM_ELEM_SELECT)) {
983 f = nullptr;
984 }
985 else {
986 break;
987 }
988 }
989 }
990 /* Last attempt: try to find any selected face */
991 if (f == nullptr) {
992 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
994 break;
995 }
996 }
997 }
998 return f; /* can still be null */
999 }
1000 return nullptr;
1001}
1002
1004{
1005 if (bm->selected.last) {
1006 BMEditSelection *ese = static_cast<BMEditSelection *>(bm->selected.last);
1007
1008 if (ese && ese->htype == BM_EDGE) {
1009 return (BMEdge *)ese->ele;
1010 }
1011 }
1012
1013 return nullptr;
1014}
1015
1017{
1018 if (bm->selected.last) {
1019 BMEditSelection *ese = static_cast<BMEditSelection *>(bm->selected.last);
1020
1021 if (ese && ese->htype == BM_VERT) {
1022 return (BMVert *)ese->ele;
1023 }
1024 }
1025
1026 return nullptr;
1027}
1028
1030{
1031 if (bm->selected.last) {
1032 BMEditSelection *ese = static_cast<BMEditSelection *>(bm->selected.last);
1033
1034 if (ese) {
1035 return ese->ele;
1036 }
1037 }
1038
1039 return nullptr;
1040}
1041
1042void BM_editselection_center(BMEditSelection *ese, float r_center[3])
1043{
1044 if (ese->htype == BM_VERT) {
1045 BMVert *eve = (BMVert *)ese->ele;
1046 copy_v3_v3(r_center, eve->co);
1047 }
1048 else if (ese->htype == BM_EDGE) {
1049 BMEdge *eed = (BMEdge *)ese->ele;
1050 mid_v3_v3v3(r_center, eed->v1->co, eed->v2->co);
1051 }
1052 else if (ese->htype == BM_FACE) {
1053 BMFace *efa = (BMFace *)ese->ele;
1054 BM_face_calc_center_median(efa, r_center);
1055 }
1056}
1057
1058void BM_editselection_normal(BMEditSelection *ese, float r_normal[3])
1059{
1060 if (ese->htype == BM_VERT) {
1061 BMVert *eve = (BMVert *)ese->ele;
1062 copy_v3_v3(r_normal, eve->no);
1063 }
1064 else if (ese->htype == BM_EDGE) {
1065 BMEdge *eed = (BMEdge *)ese->ele;
1066 float plane[3]; /* need a plane to correct the normal */
1067 float vec[3]; /* temp vec storage */
1068
1069 add_v3_v3v3(r_normal, eed->v1->no, eed->v2->no);
1070 sub_v3_v3v3(plane, eed->v2->co, eed->v1->co);
1071
1072 /* the 2 vertex normals will be close but not at right angles to the edge
1073 * for rotate about edge we want them to be at right angles, so we need to
1074 * do some extra calculation to correct the vert normals,
1075 * we need the plane for this */
1076 cross_v3_v3v3(vec, r_normal, plane);
1077 cross_v3_v3v3(r_normal, plane, vec);
1078 normalize_v3(r_normal);
1079 }
1080 else if (ese->htype == BM_FACE) {
1081 BMFace *efa = (BMFace *)ese->ele;
1082 copy_v3_v3(r_normal, efa->no);
1083 }
1084}
1085
1086void BM_editselection_plane(BMEditSelection *ese, float r_plane[3])
1087{
1088 if (ese->htype == BM_VERT) {
1089 BMVert *eve = (BMVert *)ese->ele;
1090 float vec[3] = {0.0f, 0.0f, 0.0f};
1091
1092 if (ese->prev) { /* use previously selected data to make a useful vertex plane */
1093 BM_editselection_center(ese->prev, vec);
1094 sub_v3_v3v3(r_plane, vec, eve->co);
1095 }
1096 else {
1097 /* make a fake plane that's at right-angles to the normal
1098 * we can't make a cross-vector from a vec that's the same as the vec
1099 * unlikely but possible, so make sure if the normal is (0, 0, 1)
1100 * that vec isn't the same or in the same direction even. */
1101 if (eve->no[0] < 0.5f) {
1102 vec[0] = 1.0f;
1103 }
1104 else if (eve->no[1] < 0.5f) {
1105 vec[1] = 1.0f;
1106 }
1107 else {
1108 vec[2] = 1.0f;
1109 }
1110 cross_v3_v3v3(r_plane, eve->no, vec);
1111 }
1112 normalize_v3(r_plane);
1113 }
1114 else if (ese->htype == BM_EDGE) {
1115 BMEdge *eed = (BMEdge *)ese->ele;
1116
1117 if (BM_edge_is_boundary(eed)) {
1118 sub_v3_v3v3(r_plane, eed->l->v->co, eed->l->next->v->co);
1119 }
1120 else {
1121 /* the plane is simple, it runs along the edge
1122 * however selecting different edges can swap the direction of the y axis.
1123 * this makes it less likely for the y axis of the gizmo
1124 * (running along the edge).. to flip less often.
1125 * at least its more predictable */
1126 if (eed->v2->co[1] > eed->v1->co[1]) { /* check which to do first */
1127 sub_v3_v3v3(r_plane, eed->v2->co, eed->v1->co);
1128 }
1129 else {
1130 sub_v3_v3v3(r_plane, eed->v1->co, eed->v2->co);
1131 }
1132 }
1133
1134 normalize_v3(r_plane);
1135 }
1136 else if (ese->htype == BM_FACE) {
1137 BMFace *efa = (BMFace *)ese->ele;
1138 BM_face_calc_tangent_auto(efa, r_plane);
1139 }
1140}
1141
1143{
1144 BMEditSelection *ese = MEM_callocN<BMEditSelection>("BMEdit Selection");
1145 ese->htype = ele->htype;
1146 ese->ele = (BMElem *)ele;
1147 return ese;
1148}
1149
1150/* --- Macro wrapped functions. --- */
1151
1153{
1154 return (BLI_findptr(&bm->selected, ele, offsetof(BMEditSelection, ele)) != nullptr);
1155}
1156
1158{
1159 BMEditSelection *ese = static_cast<BMEditSelection *>(
1160 BLI_findptr(&bm->selected, ele, offsetof(BMEditSelection, ele)));
1161 if (ese) {
1162 BLI_freelinkN(&bm->selected, ese);
1163 return true;
1164 }
1165 return false;
1166}
1167
1169{
1171 BLI_addtail(&(bm->selected), ese);
1172}
1173
1175{
1177 BLI_addhead(&(bm->selected), ese);
1178}
1179
1181{
1182 if (!BM_select_history_check(bm, (BMElem *)ele)) {
1184 }
1185}
1186
1193
1195{
1197 BLI_insertlinkafter(&(bm->selected), ese_ref, ese);
1198}
1199
1201{
1202 if (!BM_select_history_check(bm, (BMElem *)ele)) {
1204 }
1205}
1206/* --- End macro wrapped functions --- */
1207
1209{
1210 BLI_freelistN(&bm->selected);
1211}
1212
1214{
1215 BMEditSelection *ese, *ese_next;
1216
1217 for (ese = static_cast<BMEditSelection *>(bm->selected.first); ese; ese = ese_next) {
1218 ese_next = ese->next;
1219 if (!BM_elem_flag_test(ese->ele, BM_ELEM_SELECT)) {
1220 BLI_freelinkN(&(bm->selected), ese);
1221 }
1222 }
1223}
1224
1226{
1227 char htype_selected = 0;
1228 LISTBASE_FOREACH (const BMEditSelection *, ese, &bm->selected) {
1229 htype_selected |= ese->htype;
1230 /* Early exit if all types found. */
1231 if (htype_selected == (BM_VERT | BM_EDGE | BM_FACE)) {
1232 break;
1233 }
1234 }
1235 return htype_selected;
1236}
1237
1239{
1240 BMEditSelection *ese_last = static_cast<BMEditSelection *>(bm->selected.last);
1241 BMFace *efa = BM_mesh_active_face_get(bm, false, true);
1242
1243 ese->next = ese->prev = nullptr;
1244
1245 if (ese_last) {
1246 /* If there is an active face, use it over the last selected face. */
1247 if (ese_last->htype == BM_FACE) {
1248 if (efa) {
1249 ese->ele = (BMElem *)efa;
1250 }
1251 else {
1252 ese->ele = ese_last->ele;
1253 }
1254 ese->htype = BM_FACE;
1255 }
1256 else {
1257 ese->ele = ese_last->ele;
1258 ese->htype = ese_last->htype;
1259 }
1260 }
1261 else if (efa) {
1262 /* no edit-selection, fall back to active face */
1263 ese->ele = (BMElem *)efa;
1264 ese->htype = BM_FACE;
1265 }
1266 else {
1267 ese->ele = nullptr;
1268 return false;
1269 }
1270
1271 return true;
1272}
1273
1275{
1276 if (BLI_listbase_is_empty(&bm->selected)) {
1277 return nullptr;
1278 }
1279
1280 GHash *map = BLI_ghash_ptr_new(__func__);
1281
1282 LISTBASE_FOREACH (BMEditSelection *, ese, &bm->selected) {
1283 BLI_ghash_insert(map, ese->ele, ese);
1284 }
1285
1286 return map;
1287}
1288
1290 BMesh *bm, GHash *vert_map, GHash *edge_map, GHash *face_map, const bool use_chain)
1291{
1292
1293#ifndef NDEBUG
1294 LISTBASE_FOREACH (BMEditSelection *, ese, &bm->selected) {
1296 }
1297#endif
1298
1299 LISTBASE_FOREACH (BMEditSelection *, ese, &bm->selected) {
1301
1302 /* Only loop when (use_chain == true). */
1303 GHash *map = nullptr;
1304 switch (ese->ele->head.htype) {
1305 case BM_VERT:
1306 map = vert_map;
1307 break;
1308 case BM_EDGE:
1309 map = edge_map;
1310 break;
1311 case BM_FACE:
1312 map = face_map;
1313 break;
1314 default:
1315 BMESH_ASSERT(0);
1316 break;
1317 }
1318 if (map != nullptr) {
1319 BMElem *ele_dst = ese->ele;
1320 while (true) {
1321 BMElem *ele_dst_next = static_cast<BMElem *>(BLI_ghash_lookup(map, ele_dst));
1322 BLI_assert(ele_dst != ele_dst_next);
1323 if (ele_dst_next == nullptr) {
1324 break;
1325 }
1326 ele_dst = ele_dst_next;
1327 /* Break loop on circular reference (should never happen). */
1328 if (UNLIKELY(ele_dst == ese->ele)) {
1329 BLI_assert(0);
1330 break;
1331 }
1332 if (use_chain == false) {
1333 break;
1334 }
1335 }
1336 ese->ele = ele_dst;
1337 }
1338 }
1339
1340 /* Remove overlapping duplicates. */
1341 for (BMEditSelection *ese = static_cast<BMEditSelection *>(bm->selected.first), *ese_next; ese;
1342 ese = ese_next)
1343 {
1344 ese_next = ese->next;
1345 if (BM_ELEM_API_FLAG_TEST(ese->ele, _FLAG_OVERLAP)) {
1347 }
1348 else {
1349 BLI_freelinkN(&bm->selected, ese);
1350 }
1351 }
1352}
1353
1355 const char htype,
1356 const char hflag,
1357 const bool respecthide,
1358 const bool overwrite,
1359 const char hflag_test)
1360{
1361 const char iter_types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
1362
1363 const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
1364
1365 const char hflag_nosel = hflag & ~BM_ELEM_SELECT;
1366
1367 int i;
1368
1369 BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
1370
1371 if (hflag & BM_ELEM_SELECT) {
1373 }
1374
1375 if ((htype == (BM_VERT | BM_EDGE | BM_FACE)) && (hflag == BM_ELEM_SELECT) &&
1376 (respecthide == false) && (hflag_test == 0))
1377 {
1378 /* fast path for deselect all, avoid topology loops
1379 * since we know all will be de-selected anyway. */
1380 for (i = 0; i < 3; i++) {
1381 BMIter iter;
1382 BMElem *ele;
1383
1384 ele = static_cast<BMElem *>(BM_iter_new(&iter, bm, iter_types[i], nullptr));
1385 for (; ele; ele = static_cast<BMElem *>(BM_iter_step(&iter))) {
1387 }
1388 }
1389
1390 bm->totvertsel = bm->totedgesel = bm->totfacesel = 0;
1391 }
1392 else {
1393 for (i = 0; i < 3; i++) {
1394 BMIter iter;
1395 BMElem *ele;
1396
1397 if (htype & flag_types[i]) {
1398 ele = static_cast<BMElem *>(BM_iter_new(&iter, bm, iter_types[i], nullptr));
1399 for (; ele; ele = static_cast<BMElem *>(BM_iter_step(&iter))) {
1400
1401 if (UNLIKELY(respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN))) {
1402 /* pass */
1403 }
1404 else if (!hflag_test || BM_elem_flag_test(ele, hflag_test)) {
1405 if (hflag & BM_ELEM_SELECT) {
1406 BM_elem_select_set(bm, ele, false);
1407 }
1408 BM_elem_flag_disable(ele, hflag);
1409 }
1410 else if (overwrite) {
1411 /* no match! */
1412 if (hflag & BM_ELEM_SELECT) {
1413 BM_elem_select_set(bm, ele, true);
1414 }
1415 BM_elem_flag_enable(ele, hflag_nosel);
1416 }
1417 }
1418 }
1419 }
1420 }
1421}
1422
1424 const char htype,
1425 const char hflag,
1426 const bool respecthide,
1427 const bool overwrite,
1428 const char hflag_test)
1429{
1430 const char iter_types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
1431
1432 const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
1433
1434 /* use the nosel version when setting so under no
1435 * condition may a hidden face become selected.
1436 * Applying other flags to hidden faces is OK. */
1437 const char hflag_nosel = hflag & ~BM_ELEM_SELECT;
1438
1439 BMIter iter;
1440 BMElem *ele;
1441 int i;
1442
1443 BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
1444
1445 /* NOTE: better not attempt a fast path for selection as done with de-select
1446 * because hidden geometry and different selection modes can give different results,
1447 * we could of course check for no hidden faces and then use
1448 * quicker method but its not worth it. */
1449
1450 for (i = 0; i < 3; i++) {
1451 if (htype & flag_types[i]) {
1452 ele = static_cast<BMElem *>(BM_iter_new(&iter, bm, iter_types[i], nullptr));
1453 for (; ele; ele = static_cast<BMElem *>(BM_iter_step(&iter))) {
1454
1455 if (UNLIKELY(respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN))) {
1456 /* pass */
1457 }
1458 else if (!hflag_test || BM_elem_flag_test(ele, hflag_test)) {
1459 /* match! */
1460 if (hflag & BM_ELEM_SELECT) {
1461 BM_elem_select_set(bm, ele, true);
1462 }
1463 BM_elem_flag_enable(ele, hflag_nosel);
1464 }
1465 else if (overwrite) {
1466 /* no match! */
1467 if (hflag & BM_ELEM_SELECT) {
1468 BM_elem_select_set(bm, ele, false);
1469 }
1470 BM_elem_flag_disable(ele, hflag);
1471 }
1472 }
1473 }
1474 }
1475}
1476
1478 const char htype,
1479 const char hflag,
1480 const bool respecthide)
1481{
1482 /* call with 0 hflag_test */
1483 BM_mesh_elem_hflag_disable_test(bm, htype, hflag, respecthide, false, 0);
1484}
1485
1487 const char htype,
1488 const char hflag,
1489 const bool respecthide)
1490{
1491 /* call with 0 hflag_test */
1492 BM_mesh_elem_hflag_enable_test(bm, htype, hflag, respecthide, false, 0);
1493}
1494
1495/***************** Mesh Hiding stuff *********** */
1496
1505
1514
1515void BM_vert_hide_set(BMVert *v, const bool hide)
1516{
1517 /* vert hiding: vert + surrounding edges and faces */
1518 BLI_assert(v->head.htype == BM_VERT);
1519 if (hide) {
1521 }
1522
1524
1525 if (v->e) {
1526 BMEdge *e_iter, *e_first;
1527 e_iter = e_first = v->e;
1528 do {
1529 BM_elem_flag_set(e_iter, BM_ELEM_HIDDEN, hide);
1530 if (e_iter->l) {
1531 const BMLoop *l_radial_iter, *l_radial_first;
1532 l_radial_iter = l_radial_first = e_iter->l;
1533 do {
1534 BM_elem_flag_set(l_radial_iter->f, BM_ELEM_HIDDEN, hide);
1535 } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
1536 }
1537 } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
1538 }
1539}
1540
1541void BM_edge_hide_set(BMEdge *e, const bool hide)
1542{
1543 BLI_assert(e->head.htype == BM_EDGE);
1544 if (hide) {
1546 }
1547
1548 /* edge hiding: faces around the edge */
1549 if (e->l) {
1550 const BMLoop *l_iter, *l_first;
1551 l_iter = l_first = e->l;
1552 do {
1553 BM_elem_flag_set(l_iter->f, BM_ELEM_HIDDEN, hide);
1554 } while ((l_iter = l_iter->radial_next) != l_first);
1555 }
1556
1558
1559 /* hide vertices if necessary */
1560 if (hide) {
1563 }
1564 else {
1567 }
1568}
1569
1570void BM_face_hide_set(BMFace *f, const bool hide)
1571{
1573 if (hide) {
1575 }
1576
1578
1579 if (hide) {
1580 BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
1581 BMLoop *l_iter;
1582
1583 l_iter = l_first;
1584 do {
1585 edge_flush_hide_set(l_iter->e);
1586 } while ((l_iter = l_iter->next) != l_first);
1587
1588 l_iter = l_first;
1589 do {
1590 vert_flush_hide_set(l_iter->v);
1591 } while ((l_iter = l_iter->next) != l_first);
1592 }
1593 else {
1594 BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
1595 BMLoop *l_iter;
1596
1597 l_iter = l_first;
1598 do {
1601 } while ((l_iter = l_iter->next) != l_first);
1602 }
1603}
1604
1605void _bm_elem_hide_set(BMesh *bm, BMHeader *head, const bool hide)
1606{
1607 /* Follow convention of always deselecting before
1608 * hiding an element */
1609 switch (head->htype) {
1610 case BM_VERT:
1611 if (hide) {
1612 BM_vert_select_set(bm, (BMVert *)head, false);
1613 }
1614 BM_vert_hide_set((BMVert *)head, hide);
1615 break;
1616 case BM_EDGE:
1617 if (hide) {
1618 BM_edge_select_set(bm, (BMEdge *)head, false);
1619 }
1620 BM_edge_hide_set((BMEdge *)head, hide);
1621 break;
1622 case BM_FACE:
1623 if (hide) {
1624 BM_face_select_set(bm, (BMFace *)head, false);
1625 }
1626 BM_face_hide_set((BMFace *)head, hide);
1627 break;
1628 default:
1629 BMESH_ASSERT(0);
1630 break;
1631 }
1632}
#define BLI_assert(a)
Definition BLI_assert.h:46
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.cc:707
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_freelinkN(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:270
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:332
void BLI_addhead(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:91
void * BLI_findptr(const struct ListBase *listbase, const void *ptr, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float normalize_v3(float n[3])
struct MempoolIterData MempoolIterData
Definition BLI_task.h:200
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition BLI_task.h:221
void(* TaskParallelMempoolFunc)(void *userdata, MempoolIterData *iter, const TaskParallelTLS *__restrict tls)
Definition BLI_task.h:202
#define UNLIKELY(x)
#define ELEM(...)
@ SCE_SELECT_FACE
@ SCE_SELECT_VERTEX
@ SCE_SELECT_EDGE
Read Guarded memory(de)allocation.
#define BM_ALL_NOLOOP
#define BM_FACE_FIRST_LOOP(p)
@ BM_ELEM_HIDDEN
@ BM_ELEM_SELECT
#define BM_THREAD_LIMIT
#define BMESH_ASSERT(a)
#define BM_elem_index_get(ele)
#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_MESH(ele, iter, bm, itype)
BMIterType
BMesh Iterators.
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
#define BM_iter_new(iter, bm, itype, data)
BMesh * bm
BMVert * BM_mesh_active_vert_get(BMesh *bm)
static TaskParallelMempoolFunc recount_totsels_get_range_func(BMIterType iter_type)
void BM_select_history_clear(BMesh *bm)
static void vert_flush_hide_set(BMVert *v)
void _bm_elem_hide_set(BMesh *bm, BMHeader *head, const bool hide)
bool _bm_select_history_check(BMesh *bm, const BMHeader *ele)
static void recount_totsels_range_vert_func(void *, MempoolIterData *iter, const TaskParallelTLS *__restrict tls)
void _bm_select_history_store_head_notest(BMesh *bm, BMHeader *ele)
int BM_mesh_active_face_index_get(BMesh *bm, bool is_sloppy, bool is_selected)
void BM_vert_hide_set(BMVert *v, const bool hide)
char BM_select_history_htype_all(const BMesh *bm)
void BM_mesh_elem_hflag_enable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
int BM_mesh_active_edge_index_get(BMesh *bm)
static bool bm_edge_is_face_visible_any(const BMEdge *e)
void BM_mesh_select_mode_flush(BMesh *bm)
int BM_mesh_elem_hflag_count_disabled(BMesh *bm, const char htype, const char hflag, const bool respecthide)
static void recount_totsels_range_face_func(void *, MempoolIterData *iter, const TaskParallelTLS *__restrict tls)
void BM_mesh_select_mode_set(BMesh *bm, int selectmode)
static void recount_totsels_reduce(const void *__restrict, void *__restrict chunk_join, void *__restrict chunk)
void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
Select Face.
static bool bm_vert_is_edge_visible_any(const BMVert *v)
BMEdge * BM_mesh_active_edge_get(BMesh *bm)
void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select)
static bool recount_totsels_are_ok(BMesh *bm)
bool _bm_select_history_remove(BMesh *bm, BMHeader *ele)
void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode, BMSelectFlushFlag flag)
Select Mode Flush.
static void recount_totsels(BMesh *bm)
void _bm_select_history_store_head(BMesh *bm, BMHeader *ele)
void BM_mesh_select_mode_clean_ex(BMesh *bm, const short selectmode)
Select Mode Clean.
static void bm_mesh_select_mode_flush_vert_to_edge(BMesh *bm)
static bool bm_vert_is_edge_select_any_other(const BMVert *v, const BMEdge *e_first)
void _bm_select_history_store_after(BMesh *bm, BMEditSelection *ese_ref, BMHeader *ele)
static bool bm_edge_is_face_select_any_other(BMLoop *l_first)
void _bm_select_history_store_notest(BMesh *bm, BMHeader *ele)
BMFace * BM_mesh_active_face_get(BMesh *bm, const bool is_sloppy, const bool is_selected)
int BM_mesh_active_vert_index_get(BMesh *bm)
static int recount_totsel(BMesh *bm, BMIterType iter_type)
BMElem * BM_mesh_active_elem_get(BMesh *bm)
void BM_mesh_select_mode_clean(BMesh *bm)
static void bm_mesh_select_mode_flush_vert_to_edge_iter_fn(void *, MempoolIterData *iter, const TaskParallelTLS *__restrict tls)
void BM_editselection_center(BMEditSelection *ese, float r_center[3])
void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
Select Vert.
void BM_mesh_elem_hflag_disable_test(BMesh *bm, const char htype, const char hflag, const bool respecthide, const bool overwrite, const char hflag_test)
void _bm_select_history_store_after_notest(BMesh *bm, BMEditSelection *ese_ref, BMHeader *ele)
void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
Select Edge.
void BM_select_history_validate(BMesh *bm)
void BM_editselection_plane(BMEditSelection *ese, float r_plane[3])
void BM_edge_select_set_noflush(BMesh *bm, BMEdge *e, const bool select)
void BM_editselection_normal(BMEditSelection *ese, float r_normal[3])
static void bm_mesh_select_mode_flush_edge_to_face_iter_fn(void *, MempoolIterData *iter, const TaskParallelTLS *__restrict tls)
static void bm_mesh_select_mode_flush_edge_to_vert(BMesh *bm)
static void edge_flush_hide_set(BMEdge *e)
GHash * BM_select_history_map_create(BMesh *bm)
void BM_edge_hide_set(BMEdge *e, const bool hide)
static void bm_mesh_select_mode_flush_edge_to_face(BMesh *bm)
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
static void bm_mesh_select_mode_flush_face_to_vert_and_edge(BMesh *bm)
static int bm_mesh_flag_count(BMesh *bm, const char htype, const char hflag, const bool respecthide, const bool test_for_enabled)
void BM_mesh_active_face_set(BMesh *bm, BMFace *f)
void _bm_select_history_store(BMesh *bm, BMHeader *ele)
static void recount_totsels_range_edge_func(void *, MempoolIterData *iter, const TaskParallelTLS *__restrict tls)
static void recount_totvertsel(BMesh *bm)
void BM_select_history_merge_from_targetmap(BMesh *bm, GHash *vert_map, GHash *edge_map, GHash *face_map, const bool use_chain)
void BM_face_select_set_noflush(BMesh *bm, BMFace *f, const bool select)
static void bm_mesh_select_mode_flush_reduce_fn(const void *__restrict, void *__restrict chunk_join, void *__restrict chunk)
static void recount_totedgesel(BMesh *bm)
bool BM_mesh_select_is_mixed(const BMesh *bm)
bool BM_select_history_active_get(BMesh *bm, BMEditSelection *ese)
void BM_face_hide_set(BMFace *f, const bool hide)
static BMEditSelection * bm_select_history_create(BMHeader *ele)
int BM_mesh_elem_hflag_count_enabled(BMesh *bm, const char htype, const char hflag, const bool respecthide)
void BM_mesh_elem_hflag_enable_test(BMesh *bm, const char htype, const char hflag, const bool respecthide, const bool overwrite, const char hflag_test)
void BM_mesh_select_flush_from_verts(BMesh *bm, const bool select)
static void recount_totfacesel(BMesh *bm)
#define BM_select_history_store_notest(bm, ele)
BMSelectFlushFlag
#define BM_select_history_store_head_notest(bm, ele)
#define BMSelectFlushFlag_Default
#define BM_select_history_store_after_notest(bm, ese_ref, ele)
#define BM_select_history_check(bm, ele)
#define BM_FACE
#define BM_EDGE
#define BM_VERT
void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
void BM_face_calc_tangent_auto(const BMFace *f, float r_tangent[3])
#define BM_ELEM_API_FLAG_DISABLE(element, f)
#define BM_ELEM_API_FLAG_TEST(element, f)
#define BM_ELEM_API_FLAG_ENABLE(element, f)
@ _FLAG_OVERLAP
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
BLI_INLINE BMEdge * bmesh_disk_edge_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
#define offsetof(t, d)
#define select(A, B, C)
int count
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
BMVert * v1
BMVert * v2
struct BMLoop * l
struct BMEditSelection * next
struct BMEditSelection * prev
BMHeader head
BMHeader head
float no[3]
struct BMVert * v
struct BMEdge * e
struct BMLoop * radial_next
struct BMFace * f
struct BMLoop * next
float co[3]
float no[3]
TaskParallelReduceFunc func_reduce
Definition BLI_task.h:176
size_t userdata_chunk_size
Definition BLI_task.h:164
i
Definition text_draw.cc:230
uint8_t flag
Definition wm_window.cc:145