Blender V4.5
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_structure.hh"
28
29/* For '_FLAG_OVERLAP'. */
30#include "bmesh_private.hh"
31
32/* -------------------------------------------------------------------- */
35
39
40static void recount_totsels_range_vert_func(void * /*userdata*/,
41 MempoolIterData *iter,
42 const TaskParallelTLS *__restrict tls)
43{
44 SelectionCountChunkData *count = static_cast<SelectionCountChunkData *>(tls->userdata_chunk);
45 const BMVert *eve = (const BMVert *)iter;
47 count->selection_len += 1;
48 }
49}
50
51static void recount_totsels_range_edge_func(void * /*userdata*/,
52 MempoolIterData *iter,
53 const TaskParallelTLS *__restrict tls)
54{
55 SelectionCountChunkData *count = static_cast<SelectionCountChunkData *>(tls->userdata_chunk);
56 const BMEdge *eed = (const BMEdge *)iter;
58 count->selection_len += 1;
59 }
60}
61
62static void recount_totsels_range_face_func(void * /*userdata*/,
63 MempoolIterData *iter,
64 const TaskParallelTLS *__restrict tls)
65{
66 SelectionCountChunkData *count = static_cast<SelectionCountChunkData *>(tls->userdata_chunk);
67 const BMFace *efa = (const BMFace *)iter;
69 count->selection_len += 1;
70 }
71}
72
73static void recount_totsels_reduce(const void *__restrict /*userdata*/,
74 void *__restrict chunk_join,
75 void *__restrict chunk)
76{
77 SelectionCountChunkData *dst = static_cast<SelectionCountChunkData *>(chunk_join);
78 const SelectionCountChunkData *src = static_cast<const SelectionCountChunkData *>(chunk);
79 dst->selection_len += src->selection_len;
80}
81
83{
85
86 TaskParallelMempoolFunc range_func = nullptr;
87 if (iter_type == BM_VERTS_OF_MESH) {
89 }
90 else if (iter_type == BM_EDGES_OF_MESH) {
92 }
93 else if (iter_type == BM_FACES_OF_MESH) {
95 }
96 return range_func;
97}
98
99static int recount_totsel(BMesh *bm, BMIterType iter_type)
100{
101 const int MIN_ITER_SIZE = 1024;
102
103 TaskParallelSettings settings;
106 settings.min_iter_per_thread = MIN_ITER_SIZE;
107
109 settings.userdata_chunk = &count;
110 settings.userdata_chunk_size = sizeof(count);
111
113 BM_iter_parallel(bm, iter_type, range_func, nullptr, &settings);
114 return count.selection_len;
115}
116
118{
119 bm->totvertsel = recount_totsel(bm, BM_VERTS_OF_MESH);
120}
121
123{
124 bm->totedgesel = recount_totsel(bm, BM_EDGES_OF_MESH);
125}
126
128{
129 bm->totfacesel = recount_totsel(bm, BM_FACES_OF_MESH);
130}
131
138
139#ifndef NDEBUG
141{
142 return bm->totvertsel == recount_totsel(bm, BM_VERTS_OF_MESH) &&
143 bm->totedgesel == recount_totsel(bm, BM_EDGES_OF_MESH) &&
144 bm->totfacesel == recount_totsel(bm, BM_FACES_OF_MESH);
145}
146#endif
147
149
150/* -------------------------------------------------------------------- */
153
154static bool bm_vert_is_edge_select_any_other(const BMVert *v, const BMEdge *e_first)
155{
156 const BMEdge *e_iter = e_first;
157
158 /* start by stepping over the current edge */
159 while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first) {
160 if (BM_elem_flag_test(e_iter, BM_ELEM_SELECT)) {
161 return true;
162 }
163 }
164 return false;
165}
166
167#if 0
168static bool bm_vert_is_edge_select_any(const BMVert *v)
169{
170 if (v->e) {
171 const BMEdge *e_iter, *e_first;
172 e_iter = e_first = v->e;
173 do {
174 if (BM_elem_flag_test(e_iter, BM_ELEM_SELECT)) {
175 return true;
176 }
177 } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
178 }
179 return false;
180}
181#endif
182
184{
185 if (v->e) {
186 const BMEdge *e_iter, *e_first;
187 e_iter = e_first = v->e;
188 do {
189 if (!BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN)) {
190 return true;
191 }
192 } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
193 }
194 return false;
195}
196
198{
199 const BMLoop *l_iter = l_first;
200
201 /* start by stepping over the current face */
202 while ((l_iter = l_iter->radial_next) != l_first) {
203 if (BM_elem_flag_test(l_iter->f, BM_ELEM_SELECT)) {
204 return true;
205 }
206 }
207 return false;
208}
209
210#if 0
211static bool bm_edge_is_face_select_any(const BMEdge *e)
212{
213 if (e->l) {
214 const BMLoop *l_iter, *l_first;
215 l_iter = l_first = e->l;
216 do {
217 if (BM_elem_flag_test(l_iter->f, BM_ELEM_SELECT)) {
218 return true;
219 }
220 } while ((l_iter = l_iter->radial_next) != l_first);
221 }
222 return false;
223}
224#endif
225
227{
228 if (e->l) {
229 const BMLoop *l_iter, *l_first;
230 l_iter = l_first = e->l;
231 do {
232 if (!BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
233 return true;
234 }
235 } while ((l_iter = l_iter->radial_next) != l_first);
236 }
237 return false;
238}
239
241
242void BM_mesh_select_mode_clean_ex(BMesh *bm, const short selectmode)
243{
244 if (selectmode & SCE_SELECT_VERTEX) {
245 /* pass */
246 }
247 else if (selectmode & SCE_SELECT_EDGE) {
248 BMIter iter;
249
250 if (bm->totvertsel) {
251 BMVert *v;
252 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
254 }
255 bm->totvertsel = 0;
256 }
257
258 if (bm->totedgesel) {
259 BMEdge *e;
260 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
262 BM_vert_select_set(bm, e->v1, true);
263 BM_vert_select_set(bm, e->v2, true);
264 }
265 }
266 }
267 }
268 else if (selectmode & SCE_SELECT_FACE) {
269 BMIter iter;
270
271 if (bm->totvertsel) {
272 BMVert *v;
273 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
275 }
276 bm->totvertsel = 0;
277 }
278
279 if (bm->totedgesel) {
280 BMEdge *e;
281 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
283 }
284 bm->totedgesel = 0;
285 }
286
287 if (bm->totfacesel) {
288 BMFace *f;
289 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
291 BMLoop *l_iter, *l_first;
292 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
293 do {
294 BM_edge_select_set(bm, l_iter->e, true);
295 } while ((l_iter = l_iter->next) != l_first);
296 }
297 }
298 }
299 }
300}
301
306
307/* -------------------------------------------------------------------- */
310
314
316 MempoolIterData *iter,
317 const TaskParallelTLS *__restrict tls)
318{
319 SelectionFlushChunkData *chunk_data = static_cast<SelectionFlushChunkData *>(
320 tls->userdata_chunk);
321 BMEdge *e = (BMEdge *)iter;
322 const bool is_selected = BM_elem_flag_test(e, BM_ELEM_SELECT);
323 const bool is_hidden = BM_elem_flag_test(e, BM_ELEM_HIDDEN);
324 if (!is_hidden &&
326 {
328 chunk_data->delta_selection_len += is_selected ? 0 : 1;
329 }
330 else {
332 chunk_data->delta_selection_len += is_selected ? -1 : 0;
333 }
334}
335
337 MempoolIterData *iter,
338 const TaskParallelTLS *__restrict tls)
339{
340 SelectionFlushChunkData *chunk_data = static_cast<SelectionFlushChunkData *>(
341 tls->userdata_chunk);
342 BMFace *f = (BMFace *)iter;
343 BMLoop *l_iter;
344 BMLoop *l_first;
345 const bool is_selected = BM_elem_flag_test(f, BM_ELEM_SELECT);
346 bool ok = true;
348 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
349 do {
350 if (!BM_elem_flag_test(l_iter->e, BM_ELEM_SELECT)) {
351 ok = false;
352 break;
353 }
354 } while ((l_iter = l_iter->next) != l_first);
355 }
356 else {
357 ok = false;
358 }
359
361 if (is_selected && !ok) {
362 chunk_data->delta_selection_len -= 1;
363 }
364 else if (ok && !is_selected) {
365 chunk_data->delta_selection_len += 1;
366 }
367}
368
369static void bm_mesh_select_mode_flush_reduce_fn(const void *__restrict /*userdata*/,
370 void *__restrict chunk_join,
371 void *__restrict chunk)
372{
373 SelectionFlushChunkData *dst = static_cast<SelectionFlushChunkData *>(chunk_join);
374 const SelectionFlushChunkData *src = static_cast<const SelectionFlushChunkData *>(chunk);
376}
377
379{
380 SelectionFlushChunkData chunk_data = {0};
381
382 TaskParallelSettings settings;
384 settings.use_threading = bm->totedge >= BM_THREAD_LIMIT;
385 settings.userdata_chunk = &chunk_data;
386 settings.userdata_chunk_size = sizeof(chunk_data);
388
389 BM_iter_parallel(
391 bm->totedgesel += chunk_data.delta_selection_len;
392}
393
395{
396 SelectionFlushChunkData chunk_data = {0};
397
398 TaskParallelSettings settings;
400 settings.use_threading = bm->totface >= BM_THREAD_LIMIT;
401 settings.userdata_chunk = &chunk_data;
402 settings.userdata_chunk_size = sizeof(chunk_data);
404
405 BM_iter_parallel(
407 bm->totfacesel += chunk_data.delta_selection_len;
408}
409
410void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode, eBMSelectionFlushFLags flags)
411{
412 if (selectmode & SCE_SELECT_VERTEX) {
414 }
415
416 if (selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) {
418 }
419
420 /* Remove any deselected elements from the BMEditSelection */
422
425 }
428 }
431 }
433}
434
439
441
443{
444 BMIter eiter;
445 BMEdge *e;
446
447 BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
451 {
453 }
454 }
455
456 if (e->l && !BM_elem_flag_test(e, BM_ELEM_SELECT)) {
457 BMLoop *l_iter;
458 BMLoop *l_first;
459
460 l_iter = l_first = e->l;
461 do {
463 } while ((l_iter = l_iter->radial_next) != l_first);
464 }
465 }
466 }
467
468 /* Remove any deselected elements from the BMEditSelection */
470
472}
473
475{
476 BMEdge *e;
477 BMLoop *l_iter;
478 BMLoop *l_first;
479 BMFace *f;
480
481 BMIter eiter;
482 BMIter fiter;
483
484 bool ok;
485
486 BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
489 {
491 }
492 }
493 BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
494 ok = true;
496 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
497 do {
498 if (!BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
499 ok = false;
500 break;
501 }
502 } while ((l_iter = l_iter->next) != l_first);
503 }
504 else {
505 ok = false;
506 }
507
508 if (ok) {
510 }
511 }
512
514}
515
517{
518 BLI_assert(v->head.htype == BM_VERT);
519
521 return;
522 }
523
524 if (select) {
527 bm->totvertsel += 1;
528 }
529 }
530 else {
532 bm->totvertsel -= 1;
534 }
535 }
536}
537
539{
540 BLI_assert(e->head.htype == BM_EDGE);
541
543 return;
544 }
545
546 if (select) {
549 bm->totedgesel += 1;
550 }
551 BM_vert_select_set(bm, e->v1, true);
552 BM_vert_select_set(bm, e->v2, true);
553 }
554 else {
557 bm->totedgesel -= 1;
558 }
559
560 if ((bm->selectmode & SCE_SELECT_VERTEX) == 0) {
561 int i;
562
563 /* check if the vert is used by a selected edge */
564 for (i = 0; i < 2; i++) {
565 BMVert *v = *((&e->v1) + i);
566 if (bm_vert_is_edge_select_any_other(v, e) == false) {
567 BM_vert_select_set(bm, v, false);
568 }
569 }
570 }
571 else {
572 BM_vert_select_set(bm, e->v1, false);
573 BM_vert_select_set(bm, e->v2, false);
574 }
575 }
576}
577
579{
580 BMLoop *l_iter;
581 BMLoop *l_first;
582
584
586 return;
587 }
588
589 if (select) {
592 bm->totfacesel += 1;
593 }
594
595 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
596 do {
597 BM_vert_select_set(bm, l_iter->v, true);
598 BM_edge_select_set(bm, l_iter->e, true);
599 } while ((l_iter = l_iter->next) != l_first);
600 }
601 else {
602
605 bm->totfacesel -= 1;
606 }
615 if (bm->selectmode & SCE_SELECT_VERTEX) {
616 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
617 do {
618 BM_vert_select_set(bm, l_iter->v, false);
619 BM_edge_select_set_noflush(bm, l_iter->e, false);
620 } while ((l_iter = l_iter->next) != l_first);
621 }
622 else {
627 if (bm->selectmode & SCE_SELECT_EDGE) {
628 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
629 do {
630 BM_edge_select_set_noflush(bm, l_iter->e, false);
631 } while ((l_iter = l_iter->next) != l_first);
632 }
633 else {
634 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
635 do {
636 if (bm_edge_is_face_select_any_other(l_iter) == false) {
637 BM_edge_select_set_noflush(bm, l_iter->e, false);
638 }
639 } while ((l_iter = l_iter->next) != l_first);
640 }
641
642 /* flush down to verts */
643 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
644 do {
645 if (bm_vert_is_edge_select_any_other(l_iter->v, l_iter->e) == false) {
646 BM_vert_select_set(bm, l_iter->v, false);
647 }
648 } while ((l_iter = l_iter->next) != l_first);
649 }
650 }
651}
652
653/* -------------------------------------------------------------------- */
656
658{
659 BLI_assert(e->head.htype == BM_EDGE);
660
662 return;
663 }
664
665 if (select) {
668 bm->totedgesel += 1;
669 }
670 }
671 else {
674 bm->totedgesel -= 1;
675 }
676 }
677}
678
680{
682
684 return;
685 }
686
687 if (select) {
690 bm->totfacesel += 1;
691 }
692 }
693 else {
696 bm->totfacesel -= 1;
697 }
698 }
699}
700
702
703void BM_mesh_select_mode_set(BMesh *bm, int selectmode)
704{
705 BMIter iter;
706 BMElem *ele;
707
708 bm->selectmode = selectmode;
709
710 if (bm->selectmode & SCE_SELECT_VERTEX) {
711/* disabled because selection flushing handles these */
712#if 0
713 BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
715 }
716 BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
718 }
719#endif
721 }
722 else if (bm->selectmode & SCE_SELECT_EDGE) {
723/* disabled because selection flushing handles these */
724#if 0
725 BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
727 }
728#endif
729
730 BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
732 BM_edge_select_set(bm, (BMEdge *)ele, true);
733 }
734 }
736 }
737 else if (bm->selectmode & SCE_SELECT_FACE) {
738/* disabled because selection flushing handles these */
739#if 0
740 BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
742 }
743#endif
744 BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
746 BM_face_select_set(bm, (BMFace *)ele, true);
747 }
748 }
750 }
751}
752
757 const char htype,
758 const char hflag,
759 const bool respecthide,
760 const bool test_for_enabled)
761{
762 BMElem *ele;
763 BMIter iter;
764 int tot = 0;
765
766 BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
767
768 if (htype & BM_VERT) {
769 BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
770 if (respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) {
771 continue;
772 }
773 if (BM_elem_flag_test_bool(ele, hflag) == test_for_enabled) {
774 tot++;
775 }
776 }
777 }
778 if (htype & BM_EDGE) {
779 BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
780 if (respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) {
781 continue;
782 }
783 if (BM_elem_flag_test_bool(ele, hflag) == test_for_enabled) {
784 tot++;
785 }
786 }
787 }
788 if (htype & BM_FACE) {
789 BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
790 if (respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) {
791 continue;
792 }
793 if (BM_elem_flag_test_bool(ele, hflag) == test_for_enabled) {
794 tot++;
795 }
796 }
797 }
798
799 return tot;
800}
801
803 const char htype,
804 const char hflag,
805 const bool respecthide)
806{
807 return bm_mesh_flag_count(bm, htype, hflag, respecthide, true);
808}
809
811 const char htype,
812 const char hflag,
813 const bool respecthide)
814{
815 return bm_mesh_flag_count(bm, htype, hflag, respecthide, false);
816}
817
818void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select)
819{
820 switch (ele->head.htype) {
821 case BM_VERT:
823 break;
824 case BM_EDGE:
826 break;
827 case BM_FACE:
829 break;
830 default:
831 BLI_assert(0);
832 break;
833 }
834}
835
837{
838 bm->act_face = f;
839}
840
841int BM_mesh_active_face_index_get(BMesh *bm, bool is_sloppy, bool is_selected)
842{
843 const BMFace *f = BM_mesh_active_face_get(bm, is_sloppy, is_selected);
844 return f ? BM_elem_index_get(f) : -1;
845}
846
848{
850 return e ? BM_elem_index_get(e) : -1;
851}
852
854{
856 return v ? BM_elem_index_get(v) : -1;
857}
858
859BMFace *BM_mesh_active_face_get(BMesh *bm, const bool is_sloppy, const bool is_selected)
860{
861 if (bm->act_face && (!is_selected || BM_elem_flag_test(bm->act_face, BM_ELEM_SELECT))) {
862 return bm->act_face;
863 }
864 if (is_sloppy) {
865 BMIter iter;
866 BMFace *f = nullptr;
867 BMEditSelection *ese;
868
869 /* Find the latest non-hidden face from the BMEditSelection */
870 ese = static_cast<BMEditSelection *>(bm->selected.last);
871 for (; ese; ese = ese->prev) {
872 if (ese->htype == BM_FACE) {
873 f = (BMFace *)ese->ele;
874
876 f = nullptr;
877 }
878 else if (is_selected && !BM_elem_flag_test(f, BM_ELEM_SELECT)) {
879 f = nullptr;
880 }
881 else {
882 break;
883 }
884 }
885 }
886 /* Last attempt: try to find any selected face */
887 if (f == nullptr) {
888 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
890 break;
891 }
892 }
893 }
894 return f; /* can still be null */
895 }
896 return nullptr;
897}
898
900{
901 if (bm->selected.last) {
902 BMEditSelection *ese = static_cast<BMEditSelection *>(bm->selected.last);
903
904 if (ese && ese->htype == BM_EDGE) {
905 return (BMEdge *)ese->ele;
906 }
907 }
908
909 return nullptr;
910}
911
913{
914 if (bm->selected.last) {
915 BMEditSelection *ese = static_cast<BMEditSelection *>(bm->selected.last);
916
917 if (ese && ese->htype == BM_VERT) {
918 return (BMVert *)ese->ele;
919 }
920 }
921
922 return nullptr;
923}
924
926{
927 if (bm->selected.last) {
928 BMEditSelection *ese = static_cast<BMEditSelection *>(bm->selected.last);
929
930 if (ese) {
931 return ese->ele;
932 }
933 }
934
935 return nullptr;
936}
937
938void BM_editselection_center(BMEditSelection *ese, float r_center[3])
939{
940 if (ese->htype == BM_VERT) {
941 BMVert *eve = (BMVert *)ese->ele;
942 copy_v3_v3(r_center, eve->co);
943 }
944 else if (ese->htype == BM_EDGE) {
945 BMEdge *eed = (BMEdge *)ese->ele;
946 mid_v3_v3v3(r_center, eed->v1->co, eed->v2->co);
947 }
948 else if (ese->htype == BM_FACE) {
949 BMFace *efa = (BMFace *)ese->ele;
950 BM_face_calc_center_median(efa, r_center);
951 }
952}
953
954void BM_editselection_normal(BMEditSelection *ese, float r_normal[3])
955{
956 if (ese->htype == BM_VERT) {
957 BMVert *eve = (BMVert *)ese->ele;
958 copy_v3_v3(r_normal, eve->no);
959 }
960 else if (ese->htype == BM_EDGE) {
961 BMEdge *eed = (BMEdge *)ese->ele;
962 float plane[3]; /* need a plane to correct the normal */
963 float vec[3]; /* temp vec storage */
964
965 add_v3_v3v3(r_normal, eed->v1->no, eed->v2->no);
966 sub_v3_v3v3(plane, eed->v2->co, eed->v1->co);
967
968 /* the 2 vertex normals will be close but not at right angles to the edge
969 * for rotate about edge we want them to be at right angles, so we need to
970 * do some extra calculation to correct the vert normals,
971 * we need the plane for this */
972 cross_v3_v3v3(vec, r_normal, plane);
973 cross_v3_v3v3(r_normal, plane, vec);
974 normalize_v3(r_normal);
975 }
976 else if (ese->htype == BM_FACE) {
977 BMFace *efa = (BMFace *)ese->ele;
978 copy_v3_v3(r_normal, efa->no);
979 }
980}
981
982void BM_editselection_plane(BMEditSelection *ese, float r_plane[3])
983{
984 if (ese->htype == BM_VERT) {
985 BMVert *eve = (BMVert *)ese->ele;
986 float vec[3] = {0.0f, 0.0f, 0.0f};
987
988 if (ese->prev) { /* use previously selected data to make a useful vertex plane */
989 BM_editselection_center(ese->prev, vec);
990 sub_v3_v3v3(r_plane, vec, eve->co);
991 }
992 else {
993 /* make a fake plane that's at right-angles to the normal
994 * we can't make a cross-vector from a vec that's the same as the vec
995 * unlikely but possible, so make sure if the normal is (0, 0, 1)
996 * that vec isn't the same or in the same direction even. */
997 if (eve->no[0] < 0.5f) {
998 vec[0] = 1.0f;
999 }
1000 else if (eve->no[1] < 0.5f) {
1001 vec[1] = 1.0f;
1002 }
1003 else {
1004 vec[2] = 1.0f;
1005 }
1006 cross_v3_v3v3(r_plane, eve->no, vec);
1007 }
1008 normalize_v3(r_plane);
1009 }
1010 else if (ese->htype == BM_EDGE) {
1011 BMEdge *eed = (BMEdge *)ese->ele;
1012
1013 if (BM_edge_is_boundary(eed)) {
1014 sub_v3_v3v3(r_plane, eed->l->v->co, eed->l->next->v->co);
1015 }
1016 else {
1017 /* the plane is simple, it runs along the edge
1018 * however selecting different edges can swap the direction of the y axis.
1019 * this makes it less likely for the y axis of the gizmo
1020 * (running along the edge).. to flip less often.
1021 * at least its more predictable */
1022 if (eed->v2->co[1] > eed->v1->co[1]) { /* check which to do first */
1023 sub_v3_v3v3(r_plane, eed->v2->co, eed->v1->co);
1024 }
1025 else {
1026 sub_v3_v3v3(r_plane, eed->v1->co, eed->v2->co);
1027 }
1028 }
1029
1030 normalize_v3(r_plane);
1031 }
1032 else if (ese->htype == BM_FACE) {
1033 BMFace *efa = (BMFace *)ese->ele;
1034 BM_face_calc_tangent_auto(efa, r_plane);
1035 }
1036}
1037
1039{
1040 BMEditSelection *ese = MEM_callocN<BMEditSelection>("BMEdit Selection");
1041 ese->htype = ele->htype;
1042 ese->ele = (BMElem *)ele;
1043 return ese;
1044}
1045
1046/* --- Macro wrapped functions. --- */
1047
1049{
1050 return (BLI_findptr(&bm->selected, ele, offsetof(BMEditSelection, ele)) != nullptr);
1051}
1052
1054{
1055 BMEditSelection *ese = static_cast<BMEditSelection *>(
1056 BLI_findptr(&bm->selected, ele, offsetof(BMEditSelection, ele)));
1057 if (ese) {
1058 BLI_freelinkN(&bm->selected, ese);
1059 return true;
1060 }
1061 return false;
1062}
1063
1065{
1067 BLI_addtail(&(bm->selected), ese);
1068}
1069
1071{
1073 BLI_addhead(&(bm->selected), ese);
1074}
1075
1077{
1078 if (!BM_select_history_check(bm, (BMElem *)ele)) {
1080 }
1081}
1082
1089
1091{
1093 BLI_insertlinkafter(&(bm->selected), ese_ref, ese);
1094}
1095
1097{
1098 if (!BM_select_history_check(bm, (BMElem *)ele)) {
1100 }
1101}
1102/* --- End macro wrapped functions --- */
1103
1105{
1106 BLI_freelistN(&bm->selected);
1107}
1108
1110{
1111 BMEditSelection *ese, *ese_next;
1112
1113 for (ese = static_cast<BMEditSelection *>(bm->selected.first); ese; ese = ese_next) {
1114 ese_next = ese->next;
1115 if (!BM_elem_flag_test(ese->ele, BM_ELEM_SELECT)) {
1116 BLI_freelinkN(&(bm->selected), ese);
1117 }
1118 }
1119}
1120
1122{
1123 BMEditSelection *ese_last = static_cast<BMEditSelection *>(bm->selected.last);
1124 BMFace *efa = BM_mesh_active_face_get(bm, false, true);
1125
1126 ese->next = ese->prev = nullptr;
1127
1128 if (ese_last) {
1129 /* If there is an active face, use it over the last selected face. */
1130 if (ese_last->htype == BM_FACE) {
1131 if (efa) {
1132 ese->ele = (BMElem *)efa;
1133 }
1134 else {
1135 ese->ele = ese_last->ele;
1136 }
1137 ese->htype = BM_FACE;
1138 }
1139 else {
1140 ese->ele = ese_last->ele;
1141 ese->htype = ese_last->htype;
1142 }
1143 }
1144 else if (efa) {
1145 /* no edit-selection, fall back to active face */
1146 ese->ele = (BMElem *)efa;
1147 ese->htype = BM_FACE;
1148 }
1149 else {
1150 ese->ele = nullptr;
1151 return false;
1152 }
1153
1154 return true;
1155}
1156
1158{
1159 if (BLI_listbase_is_empty(&bm->selected)) {
1160 return nullptr;
1161 }
1162
1163 GHash *map = BLI_ghash_ptr_new(__func__);
1164
1165 LISTBASE_FOREACH (BMEditSelection *, ese, &bm->selected) {
1166 BLI_ghash_insert(map, ese->ele, ese);
1167 }
1168
1169 return map;
1170}
1171
1173 BMesh *bm, GHash *vert_map, GHash *edge_map, GHash *face_map, const bool use_chain)
1174{
1175
1176#ifndef NDEBUG
1177 LISTBASE_FOREACH (BMEditSelection *, ese, &bm->selected) {
1179 }
1180#endif
1181
1182 LISTBASE_FOREACH (BMEditSelection *, ese, &bm->selected) {
1184
1185 /* Only loop when (use_chain == true). */
1186 GHash *map = nullptr;
1187 switch (ese->ele->head.htype) {
1188 case BM_VERT:
1189 map = vert_map;
1190 break;
1191 case BM_EDGE:
1192 map = edge_map;
1193 break;
1194 case BM_FACE:
1195 map = face_map;
1196 break;
1197 default:
1198 BMESH_ASSERT(0);
1199 break;
1200 }
1201 if (map != nullptr) {
1202 BMElem *ele_dst = ese->ele;
1203 while (true) {
1204 BMElem *ele_dst_next = static_cast<BMElem *>(BLI_ghash_lookup(map, ele_dst));
1205 BLI_assert(ele_dst != ele_dst_next);
1206 if (ele_dst_next == nullptr) {
1207 break;
1208 }
1209 ele_dst = ele_dst_next;
1210 /* Break loop on circular reference (should never happen). */
1211 if (UNLIKELY(ele_dst == ese->ele)) {
1212 BLI_assert(0);
1213 break;
1214 }
1215 if (use_chain == false) {
1216 break;
1217 }
1218 }
1219 ese->ele = ele_dst;
1220 }
1221 }
1222
1223 /* Remove overlapping duplicates. */
1224 for (BMEditSelection *ese = static_cast<BMEditSelection *>(bm->selected.first), *ese_next; ese;
1225 ese = ese_next)
1226 {
1227 ese_next = ese->next;
1228 if (BM_ELEM_API_FLAG_TEST(ese->ele, _FLAG_OVERLAP)) {
1230 }
1231 else {
1232 BLI_freelinkN(&bm->selected, ese);
1233 }
1234 }
1235}
1236
1238 const char htype,
1239 const char hflag,
1240 const bool respecthide,
1241 const bool overwrite,
1242 const char hflag_test)
1243{
1244 const char iter_types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
1245
1246 const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
1247
1248 const char hflag_nosel = hflag & ~BM_ELEM_SELECT;
1249
1250 int i;
1251
1252 BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
1253
1254 if (hflag & BM_ELEM_SELECT) {
1256 }
1257
1258 if ((htype == (BM_VERT | BM_EDGE | BM_FACE)) && (hflag == BM_ELEM_SELECT) &&
1259 (respecthide == false) && (hflag_test == 0))
1260 {
1261 /* fast path for deselect all, avoid topology loops
1262 * since we know all will be de-selected anyway. */
1263 for (i = 0; i < 3; i++) {
1264 BMIter iter;
1265 BMElem *ele;
1266
1267 ele = static_cast<BMElem *>(BM_iter_new(&iter, bm, iter_types[i], nullptr));
1268 for (; ele; ele = static_cast<BMElem *>(BM_iter_step(&iter))) {
1270 }
1271 }
1272
1273 bm->totvertsel = bm->totedgesel = bm->totfacesel = 0;
1274 }
1275 else {
1276 for (i = 0; i < 3; i++) {
1277 BMIter iter;
1278 BMElem *ele;
1279
1280 if (htype & flag_types[i]) {
1281 ele = static_cast<BMElem *>(BM_iter_new(&iter, bm, iter_types[i], nullptr));
1282 for (; ele; ele = static_cast<BMElem *>(BM_iter_step(&iter))) {
1283
1284 if (UNLIKELY(respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN))) {
1285 /* pass */
1286 }
1287 else if (!hflag_test || BM_elem_flag_test(ele, hflag_test)) {
1288 if (hflag & BM_ELEM_SELECT) {
1289 BM_elem_select_set(bm, ele, false);
1290 }
1291 BM_elem_flag_disable(ele, hflag);
1292 }
1293 else if (overwrite) {
1294 /* no match! */
1295 if (hflag & BM_ELEM_SELECT) {
1296 BM_elem_select_set(bm, ele, true);
1297 }
1298 BM_elem_flag_enable(ele, hflag_nosel);
1299 }
1300 }
1301 }
1302 }
1303 }
1304}
1305
1307 const char htype,
1308 const char hflag,
1309 const bool respecthide,
1310 const bool overwrite,
1311 const char hflag_test)
1312{
1313 const char iter_types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
1314
1315 const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
1316
1317 /* use the nosel version when setting so under no
1318 * condition may a hidden face become selected.
1319 * Applying other flags to hidden faces is OK. */
1320 const char hflag_nosel = hflag & ~BM_ELEM_SELECT;
1321
1322 BMIter iter;
1323 BMElem *ele;
1324 int i;
1325
1326 BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
1327
1328 /* NOTE: better not attempt a fast path for selection as done with de-select
1329 * because hidden geometry and different selection modes can give different results,
1330 * we could of course check for no hidden faces and then use
1331 * quicker method but its not worth it. */
1332
1333 for (i = 0; i < 3; i++) {
1334 if (htype & flag_types[i]) {
1335 ele = static_cast<BMElem *>(BM_iter_new(&iter, bm, iter_types[i], nullptr));
1336 for (; ele; ele = static_cast<BMElem *>(BM_iter_step(&iter))) {
1337
1338 if (UNLIKELY(respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN))) {
1339 /* pass */
1340 }
1341 else if (!hflag_test || BM_elem_flag_test(ele, hflag_test)) {
1342 /* match! */
1343 if (hflag & BM_ELEM_SELECT) {
1344 BM_elem_select_set(bm, ele, true);
1345 }
1346 BM_elem_flag_enable(ele, hflag_nosel);
1347 }
1348 else if (overwrite) {
1349 /* no match! */
1350 if (hflag & BM_ELEM_SELECT) {
1351 BM_elem_select_set(bm, ele, false);
1352 }
1353 BM_elem_flag_disable(ele, hflag);
1354 }
1355 }
1356 }
1357 }
1358}
1359
1361 const char htype,
1362 const char hflag,
1363 const bool respecthide)
1364{
1365 /* call with 0 hflag_test */
1366 BM_mesh_elem_hflag_disable_test(bm, htype, hflag, respecthide, false, 0);
1367}
1368
1370 const char htype,
1371 const char hflag,
1372 const bool respecthide)
1373{
1374 /* call with 0 hflag_test */
1375 BM_mesh_elem_hflag_enable_test(bm, htype, hflag, respecthide, false, 0);
1376}
1377
1378/***************** Mesh Hiding stuff *********** */
1379
1388
1397
1398void BM_vert_hide_set(BMVert *v, const bool hide)
1399{
1400 /* vert hiding: vert + surrounding edges and faces */
1401 BLI_assert(v->head.htype == BM_VERT);
1402 if (hide) {
1404 }
1405
1407
1408 if (v->e) {
1409 BMEdge *e_iter, *e_first;
1410 e_iter = e_first = v->e;
1411 do {
1412 BM_elem_flag_set(e_iter, BM_ELEM_HIDDEN, hide);
1413 if (e_iter->l) {
1414 const BMLoop *l_radial_iter, *l_radial_first;
1415 l_radial_iter = l_radial_first = e_iter->l;
1416 do {
1417 BM_elem_flag_set(l_radial_iter->f, BM_ELEM_HIDDEN, hide);
1418 } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
1419 }
1420 } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
1421 }
1422}
1423
1424void BM_edge_hide_set(BMEdge *e, const bool hide)
1425{
1426 BLI_assert(e->head.htype == BM_EDGE);
1427 if (hide) {
1429 }
1430
1431 /* edge hiding: faces around the edge */
1432 if (e->l) {
1433 const BMLoop *l_iter, *l_first;
1434 l_iter = l_first = e->l;
1435 do {
1436 BM_elem_flag_set(l_iter->f, BM_ELEM_HIDDEN, hide);
1437 } while ((l_iter = l_iter->radial_next) != l_first);
1438 }
1439
1441
1442 /* hide vertices if necessary */
1443 if (hide) {
1446 }
1447 else {
1450 }
1451}
1452
1453void BM_face_hide_set(BMFace *f, const bool hide)
1454{
1456 if (hide) {
1458 }
1459
1461
1462 if (hide) {
1463 BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
1464 BMLoop *l_iter;
1465
1466 l_iter = l_first;
1467 do {
1468 edge_flush_hide_set(l_iter->e);
1469 } while ((l_iter = l_iter->next) != l_first);
1470
1471 l_iter = l_first;
1472 do {
1473 vert_flush_hide_set(l_iter->v);
1474 } while ((l_iter = l_iter->next) != l_first);
1475 }
1476 else {
1477 BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
1478 BMLoop *l_iter;
1479
1480 l_iter = l_first;
1481 do {
1484 } while ((l_iter = l_iter->next) != l_first);
1485 }
1486}
1487
1488void _bm_elem_hide_set(BMesh *bm, BMHeader *head, const bool hide)
1489{
1490 /* Follow convention of always deselecting before
1491 * hiding an element */
1492 switch (head->htype) {
1493 case BM_VERT:
1494 if (hide) {
1495 BM_vert_select_set(bm, (BMVert *)head, false);
1496 }
1497 BM_vert_hide_set((BMVert *)head, hide);
1498 break;
1499 case BM_EDGE:
1500 if (hide) {
1501 BM_edge_select_set(bm, (BMEdge *)head, false);
1502 }
1503 BM_edge_hide_set((BMEdge *)head, hide);
1504 break;
1505 case BM_FACE:
1506 if (hide) {
1507 BM_face_select_set(bm, (BMFace *)head, false);
1508 }
1509 BM_face_hide_set((BMFace *)head, hide);
1510 break;
1511 default:
1512 BMESH_ASSERT(0);
1513 break;
1514 }
1515}
#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.
@ BM_ELEM_HIDDEN
@ BM_ELEM_SELECT
#define BM_ALL_NOLOOP
#define BM_FACE_FIRST_LOOP(p)
#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)
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)
void BM_mesh_select_flush(BMesh *bm)
static bool recount_totsels_are_ok(BMesh *bm)
bool _bm_select_history_remove(BMesh *bm, BMHeader *ele)
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)
void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode, eBMSelectionFlushFLags flags)
Select Mode Flush.
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)
void BM_mesh_deselect_flush(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 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_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)
static void recount_totfacesel(BMesh *bm)
#define BM_select_history_store_notest(bm, ele)
#define BM_select_history_store_head_notest(bm, ele)
#define BM_select_history_store_after_notest(bm, ese_ref, ele)
#define BM_select_history_check(bm, ele)
eBMSelectionFlushFLags
@ BM_SELECT_LEN_FLUSH_RECALC_ALL
@ BM_SELECT_LEN_FLUSH_RECALC_EDGE
@ BM_SELECT_LEN_FLUSH_RECALC_FACE
@ BM_SELECT_LEN_FLUSH_RECALC_VERT
#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)
@ _FLAG_OVERLAP
#define BM_ELEM_API_FLAG_ENABLE(element, f)
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