Blender  V3.3
bmesh_marking.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
14 #include <stddef.h>
15 
16 #include "MEM_guardedalloc.h"
17 
18 #include "DNA_scene_types.h"
19 
20 #include "BLI_listbase.h"
21 #include "BLI_math.h"
22 #include "BLI_task.h"
23 
24 #include "bmesh.h"
25 #include "bmesh_structure.h"
26 
27 /* For '_FLAG_OVERLAP'. */
28 #include "bmesh_private.h"
29 
30 /* -------------------------------------------------------------------- */
34 typedef struct SelectionCountChunkData {
37 
38 static void recount_totsels_range_vert_func(void *UNUSED(userdata),
39  MempoolIterData *iter,
40  const TaskParallelTLS *__restrict tls)
41 {
42  SelectionCountChunkData *count = tls->userdata_chunk;
43  const BMVert *eve = (const BMVert *)iter;
45  count->selection_len += 1;
46  }
47 }
48 
49 static void recount_totsels_range_edge_func(void *UNUSED(userdata),
50  MempoolIterData *iter,
51  const TaskParallelTLS *__restrict tls)
52 {
53  SelectionCountChunkData *count = tls->userdata_chunk;
54  const BMEdge *eed = (const BMEdge *)iter;
56  count->selection_len += 1;
57  }
58 }
59 
60 static void recount_totsels_range_face_func(void *UNUSED(userdata),
61  MempoolIterData *iter,
62  const TaskParallelTLS *__restrict tls)
63 {
64  SelectionCountChunkData *count = tls->userdata_chunk;
65  const BMFace *efa = (const BMFace *)iter;
67  count->selection_len += 1;
68  }
69 }
70 
71 static void recount_totsels_reduce(const void *__restrict UNUSED(userdata),
72  void *__restrict chunk_join,
73  void *__restrict chunk)
74 {
75  SelectionCountChunkData *dst = chunk_join;
76  const SelectionCountChunkData *src = chunk;
77  dst->selection_len += src->selection_len;
78 }
79 
81 {
83 
84  TaskParallelMempoolFunc range_func = NULL;
85  if (iter_type == BM_VERTS_OF_MESH) {
87  }
88  else if (iter_type == BM_EDGES_OF_MESH) {
90  }
91  else if (iter_type == BM_FACES_OF_MESH) {
93  }
94  return range_func;
95 }
96 
97 static int recount_totsel(BMesh *bm, BMIterType iter_type)
98 {
99  const int MIN_ITER_SIZE = 1024;
100 
101  TaskParallelSettings settings;
104  settings.min_iter_per_thread = MIN_ITER_SIZE;
105 
107  settings.userdata_chunk = &count;
108  settings.userdata_chunk_size = sizeof(count);
109 
111  BM_iter_parallel(bm, iter_type, range_func, NULL, &settings);
112  return count.selection_len;
113 }
114 
116 {
118 }
119 
121 {
123 }
124 
126 {
128 }
129 
130 static void recount_totsels(BMesh *bm)
131 {
135 }
136 
137 #ifndef NDEBUG
139 {
143 }
144 #endif
145 
148 /* -------------------------------------------------------------------- */
152 static bool bm_vert_is_edge_select_any_other(const BMVert *v, const BMEdge *e_first)
153 {
154  const BMEdge *e_iter = e_first;
155 
156  /* start by stepping over the current edge */
157  while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first) {
158  if (BM_elem_flag_test(e_iter, BM_ELEM_SELECT)) {
159  return true;
160  }
161  }
162  return false;
163 }
164 
165 #if 0
166 static bool bm_vert_is_edge_select_any(const BMVert *v)
167 {
168  if (v->e) {
169  const BMEdge *e_iter, *e_first;
170  e_iter = e_first = v->e;
171  do {
172  if (BM_elem_flag_test(e_iter, BM_ELEM_SELECT)) {
173  return true;
174  }
175  } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
176  }
177  return false;
178 }
179 #endif
180 
182 {
183  if (v->e) {
184  const BMEdge *e_iter, *e_first;
185  e_iter = e_first = v->e;
186  do {
187  if (!BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN)) {
188  return true;
189  }
190  } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
191  }
192  return false;
193 }
194 
196 {
197  const BMLoop *l_iter = l_first;
198 
199  /* start by stepping over the current face */
200  while ((l_iter = l_iter->radial_next) != l_first) {
201  if (BM_elem_flag_test(l_iter->f, BM_ELEM_SELECT)) {
202  return true;
203  }
204  }
205  return false;
206 }
207 
208 #if 0
209 static bool bm_edge_is_face_select_any(const BMEdge *e)
210 {
211  if (e->l) {
212  const BMLoop *l_iter, *l_first;
213  l_iter = l_first = e->l;
214  do {
215  if (BM_elem_flag_test(l_iter->f, BM_ELEM_SELECT)) {
216  return true;
217  }
218  } while ((l_iter = l_iter->radial_next) != l_first);
219  }
220  return false;
221 }
222 #endif
223 
225 {
226  if (e->l) {
227  const BMLoop *l_iter, *l_first;
228  l_iter = l_first = e->l;
229  do {
230  if (!BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
231  return true;
232  }
233  } while ((l_iter = l_iter->radial_next) != l_first);
234  }
235  return false;
236 }
237 
240 void BM_mesh_select_mode_clean_ex(BMesh *bm, const short selectmode)
241 {
242  if (selectmode & SCE_SELECT_VERTEX) {
243  /* pass */
244  }
245  else if (selectmode & SCE_SELECT_EDGE) {
246  BMIter iter;
247 
248  if (bm->totvertsel) {
249  BMVert *v;
250  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
252  }
253  bm->totvertsel = 0;
254  }
255 
256  if (bm->totedgesel) {
257  BMEdge *e;
258  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
260  BM_vert_select_set(bm, e->v1, true);
261  BM_vert_select_set(bm, e->v2, true);
262  }
263  }
264  }
265  }
266  else if (selectmode & SCE_SELECT_FACE) {
267  BMIter iter;
268 
269  if (bm->totvertsel) {
270  BMVert *v;
271  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
273  }
274  bm->totvertsel = 0;
275  }
276 
277  if (bm->totedgesel) {
278  BMEdge *e;
279  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
281  }
282  bm->totedgesel = 0;
283  }
284 
285  if (bm->totfacesel) {
286  BMFace *f;
287  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
289  BMLoop *l_iter, *l_first;
290  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
291  do {
292  BM_edge_select_set(bm, l_iter->e, true);
293  } while ((l_iter = l_iter->next) != l_first);
294  }
295  }
296  }
297  }
298 }
299 
301 {
303 }
304 
305 /* -------------------------------------------------------------------- */
309 typedef struct SelectionFlushChunkData {
312 
314  MempoolIterData *iter,
315  const TaskParallelTLS *__restrict tls)
316 {
317  SelectionFlushChunkData *chunk_data = tls->userdata_chunk;
318  BMEdge *e = (BMEdge *)iter;
319  const bool is_selected = BM_elem_flag_test(e, BM_ELEM_SELECT);
320  const bool is_hidden = BM_elem_flag_test(e, BM_ELEM_HIDDEN);
321  if (!is_hidden &&
324  chunk_data->delta_selection_len += is_selected ? 0 : 1;
325  }
326  else {
328  chunk_data->delta_selection_len += is_selected ? -1 : 0;
329  }
330 }
331 
333  MempoolIterData *iter,
334  const TaskParallelTLS *__restrict tls)
335 {
336  SelectionFlushChunkData *chunk_data = tls->userdata_chunk;
337  BMFace *f = (BMFace *)iter;
338  BMLoop *l_iter;
339  BMLoop *l_first;
340  const bool is_selected = BM_elem_flag_test(f, BM_ELEM_SELECT);
341  bool ok = true;
343  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
344  do {
345  if (!BM_elem_flag_test(l_iter->e, BM_ELEM_SELECT)) {
346  ok = false;
347  break;
348  }
349  } while ((l_iter = l_iter->next) != l_first);
350  }
351  else {
352  ok = false;
353  }
354 
356  if (is_selected && !ok) {
357  chunk_data->delta_selection_len -= 1;
358  }
359  else if (ok && !is_selected) {
360  chunk_data->delta_selection_len += 1;
361  }
362 }
363 
364 static void bm_mesh_select_mode_flush_reduce_fn(const void *__restrict UNUSED(userdata),
365  void *__restrict chunk_join,
366  void *__restrict chunk)
367 {
368  SelectionFlushChunkData *dst = chunk_join;
369  const SelectionFlushChunkData *src = chunk;
370  dst->delta_selection_len += src->delta_selection_len;
371 }
372 
374 {
375  SelectionFlushChunkData chunk_data = {0};
376 
377  TaskParallelSettings settings;
379  settings.use_threading = bm->totedge >= BM_OMP_LIMIT;
380  settings.userdata_chunk = &chunk_data;
381  settings.userdata_chunk_size = sizeof(chunk_data);
383 
384  BM_iter_parallel(
386  bm->totedgesel += chunk_data.delta_selection_len;
387 }
388 
390 {
391  SelectionFlushChunkData chunk_data = {0};
392 
393  TaskParallelSettings settings;
395  settings.use_threading = bm->totface >= BM_OMP_LIMIT;
396  settings.userdata_chunk = &chunk_data;
397  settings.userdata_chunk_size = sizeof(chunk_data);
399 
400  BM_iter_parallel(
402  bm->totfacesel += chunk_data.delta_selection_len;
403 }
404 
405 void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode, eBMSelectionFlushFLags flags)
406 {
407  if (selectmode & SCE_SELECT_VERTEX) {
409  }
410 
411  if (selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) {
413  }
414 
415  /* Remove any deselected elements from the BMEditSelection */
417 
418  if (flags & BM_SELECT_LEN_FLUSH_RECALC_VERT) {
420  }
421  if (flags & BM_SELECT_LEN_FLUSH_RECALC_EDGE) {
423  }
424  if (flags & BM_SELECT_LEN_FLUSH_RECALC_FACE) {
426  }
428 }
429 
431 {
433 }
434 
438 {
439  BMIter eiter;
440  BMEdge *e;
441 
442  BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
445  if (!BM_elem_flag_test(e->v1, BM_ELEM_SELECT) ||
448  }
449  }
450 
451  if (e->l && !BM_elem_flag_test(e, BM_ELEM_SELECT)) {
452  BMLoop *l_iter;
453  BMLoop *l_first;
454 
455  l_iter = l_first = e->l;
456  do {
458  } while ((l_iter = l_iter->radial_next) != l_first);
459  }
460  }
461  }
462 
463  /* Remove any deselected elements from the BMEditSelection */
465 
467 }
468 
470 {
471  BMEdge *e;
472  BMLoop *l_iter;
473  BMLoop *l_first;
474  BMFace *f;
475 
476  BMIter eiter;
477  BMIter fiter;
478 
479  bool ok;
480 
481  BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
485  }
486  }
487  BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
488  ok = true;
490  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
491  do {
492  if (!BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
493  ok = false;
494  break;
495  }
496  } while ((l_iter = l_iter->next) != l_first);
497  }
498  else {
499  ok = false;
500  }
501 
502  if (ok) {
504  }
505  }
506 
508 }
509 
510 void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
511 {
513 
515  return;
516  }
517 
518  if (select) {
521  bm->totvertsel += 1;
522  }
523  }
524  else {
526  bm->totvertsel -= 1;
528  }
529  }
530 }
531 
532 void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
533 {
535 
537  return;
538  }
539 
540  if (select) {
543  bm->totedgesel += 1;
544  }
545  BM_vert_select_set(bm, e->v1, true);
546  BM_vert_select_set(bm, e->v2, true);
547  }
548  else {
551  bm->totedgesel -= 1;
552  }
553 
554  if ((bm->selectmode & SCE_SELECT_VERTEX) == 0) {
555  int i;
556 
557  /* check if the vert is used by a selected edge */
558  for (i = 0; i < 2; i++) {
559  BMVert *v = *((&e->v1) + i);
560  if (bm_vert_is_edge_select_any_other(v, e) == false) {
561  BM_vert_select_set(bm, v, false);
562  }
563  }
564  }
565  else {
566  BM_vert_select_set(bm, e->v1, false);
567  BM_vert_select_set(bm, e->v2, false);
568  }
569  }
570 }
571 
572 void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
573 {
574  BMLoop *l_iter;
575  BMLoop *l_first;
576 
577  BLI_assert(f->head.htype == BM_FACE);
578 
580  return;
581  }
582 
583  if (select) {
586  bm->totfacesel += 1;
587  }
588 
589  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
590  do {
591  BM_vert_select_set(bm, l_iter->v, true);
592  BM_edge_select_set(bm, l_iter->e, true);
593  } while ((l_iter = l_iter->next) != l_first);
594  }
595  else {
596 
599  bm->totfacesel -= 1;
600  }
610  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
611  do {
612  BM_vert_select_set(bm, l_iter->v, false);
613  BM_edge_select_set_noflush(bm, l_iter->e, false);
614  } while ((l_iter = l_iter->next) != l_first);
615  }
616  else {
621  if (bm->selectmode & SCE_SELECT_EDGE) {
622  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
623  do {
624  BM_edge_select_set_noflush(bm, l_iter->e, false);
625  } while ((l_iter = l_iter->next) != l_first);
626  }
627  else {
628  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
629  do {
630  if (bm_edge_is_face_select_any_other(l_iter) == false) {
631  BM_edge_select_set_noflush(bm, l_iter->e, false);
632  }
633  } while ((l_iter = l_iter->next) != l_first);
634  }
635 
636  /* flush down to verts */
637  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
638  do {
639  if (bm_vert_is_edge_select_any_other(l_iter->v, l_iter->e) == false) {
640  BM_vert_select_set(bm, l_iter->v, false);
641  }
642  } while ((l_iter = l_iter->next) != l_first);
643  }
644  }
645 }
646 
647 /* -------------------------------------------------------------------- */
652 {
654 
656  return;
657  }
658 
659  if (select) {
662  bm->totedgesel += 1;
663  }
664  }
665  else {
668  bm->totedgesel -= 1;
669  }
670  }
671 }
672 
674 {
675  BLI_assert(f->head.htype == BM_FACE);
676 
678  return;
679  }
680 
681  if (select) {
684  bm->totfacesel += 1;
685  }
686  }
687  else {
690  bm->totfacesel -= 1;
691  }
692  }
693 }
694 
697 void BM_mesh_select_mode_set(BMesh *bm, int selectmode)
698 {
699  BMIter iter;
700  BMElem *ele;
701 
702  bm->selectmode = selectmode;
703 
705  /* disabled because selection flushing handles these */
706 #if 0
707  BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
709  }
710  BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
712  }
713 #endif
715  }
716  else if (bm->selectmode & SCE_SELECT_EDGE) {
717  /* disabled because selection flushing handles these */
718 #if 0
719  BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
721  }
722 #endif
723 
724  BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
725  if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
726  BM_edge_select_set(bm, (BMEdge *)ele, true);
727  }
728  }
730  }
731  else if (bm->selectmode & SCE_SELECT_FACE) {
732  /* disabled because selection flushing handles these */
733 #if 0
734  BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
736  }
737 #endif
738  BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
739  if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
740  BM_face_select_set(bm, (BMFace *)ele, true);
741  }
742  }
744  }
745 }
746 
751  const char htype,
752  const char hflag,
753  const bool respecthide,
754  const bool test_for_enabled)
755 {
756  BMElem *ele;
757  BMIter iter;
758  int tot = 0;
759 
760  BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
761 
762  if (htype & BM_VERT) {
763  BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
764  if (respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) {
765  continue;
766  }
767  if (BM_elem_flag_test_bool(ele, hflag) == test_for_enabled) {
768  tot++;
769  }
770  }
771  }
772  if (htype & BM_EDGE) {
773  BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
774  if (respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) {
775  continue;
776  }
777  if (BM_elem_flag_test_bool(ele, hflag) == test_for_enabled) {
778  tot++;
779  }
780  }
781  }
782  if (htype & BM_FACE) {
783  BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
784  if (respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) {
785  continue;
786  }
787  if (BM_elem_flag_test_bool(ele, hflag) == test_for_enabled) {
788  tot++;
789  }
790  }
791  }
792 
793  return tot;
794 }
795 
797  const char htype,
798  const char hflag,
799  const bool respecthide)
800 {
801  return bm_mesh_flag_count(bm, htype, hflag, respecthide, true);
802 }
803 
805  const char htype,
806  const char hflag,
807  const bool respecthide)
808 {
809  return bm_mesh_flag_count(bm, htype, hflag, respecthide, false);
810 }
811 
812 void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select)
813 {
814  switch (ele->head.htype) {
815  case BM_VERT:
817  break;
818  case BM_EDGE:
820  break;
821  case BM_FACE:
823  break;
824  default:
825  BLI_assert(0);
826  break;
827  }
828 }
829 
831 {
832  bm->act_face = f;
833 }
834 
835 BMFace *BM_mesh_active_face_get(BMesh *bm, const bool is_sloppy, const bool is_selected)
836 {
837  if (bm->act_face && (!is_selected || BM_elem_flag_test(bm->act_face, BM_ELEM_SELECT))) {
838  return bm->act_face;
839  }
840  if (is_sloppy) {
841  BMIter iter;
842  BMFace *f = NULL;
843  BMEditSelection *ese;
844 
845  /* Find the latest non-hidden face from the BMEditSelection */
846  ese = bm->selected.last;
847  for (; ese; ese = ese->prev) {
848  if (ese->htype == BM_FACE) {
849  f = (BMFace *)ese->ele;
850 
852  f = NULL;
853  }
854  else if (is_selected && !BM_elem_flag_test(f, BM_ELEM_SELECT)) {
855  f = NULL;
856  }
857  else {
858  break;
859  }
860  }
861  }
862  /* Last attempt: try to find any selected face */
863  if (f == NULL) {
864  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
866  break;
867  }
868  }
869  }
870  return f; /* can still be null */
871  }
872  return NULL;
873 }
874 
876 {
877  if (bm->selected.last) {
879 
880  if (ese && ese->htype == BM_EDGE) {
881  return (BMEdge *)ese->ele;
882  }
883  }
884 
885  return NULL;
886 }
887 
889 {
890  if (bm->selected.last) {
892 
893  if (ese && ese->htype == BM_VERT) {
894  return (BMVert *)ese->ele;
895  }
896  }
897 
898  return NULL;
899 }
900 
902 {
903  if (bm->selected.last) {
905 
906  if (ese) {
907  return ese->ele;
908  }
909  }
910 
911  return NULL;
912 }
913 
914 void BM_editselection_center(BMEditSelection *ese, float r_center[3])
915 {
916  if (ese->htype == BM_VERT) {
917  BMVert *eve = (BMVert *)ese->ele;
918  copy_v3_v3(r_center, eve->co);
919  }
920  else if (ese->htype == BM_EDGE) {
921  BMEdge *eed = (BMEdge *)ese->ele;
922  mid_v3_v3v3(r_center, eed->v1->co, eed->v2->co);
923  }
924  else if (ese->htype == BM_FACE) {
925  BMFace *efa = (BMFace *)ese->ele;
926  BM_face_calc_center_median(efa, r_center);
927  }
928 }
929 
930 void BM_editselection_normal(BMEditSelection *ese, float r_normal[3])
931 {
932  if (ese->htype == BM_VERT) {
933  BMVert *eve = (BMVert *)ese->ele;
934  copy_v3_v3(r_normal, eve->no);
935  }
936  else if (ese->htype == BM_EDGE) {
937  BMEdge *eed = (BMEdge *)ese->ele;
938  float plane[3]; /* need a plane to correct the normal */
939  float vec[3]; /* temp vec storage */
940 
941  add_v3_v3v3(r_normal, eed->v1->no, eed->v2->no);
942  sub_v3_v3v3(plane, eed->v2->co, eed->v1->co);
943 
944  /* the 2 vertex normals will be close but not at right angles to the edge
945  * for rotate about edge we want them to be at right angles, so we need to
946  * do some extra calculation to correct the vert normals,
947  * we need the plane for this */
948  cross_v3_v3v3(vec, r_normal, plane);
949  cross_v3_v3v3(r_normal, plane, vec);
950  normalize_v3(r_normal);
951  }
952  else if (ese->htype == BM_FACE) {
953  BMFace *efa = (BMFace *)ese->ele;
954  copy_v3_v3(r_normal, efa->no);
955  }
956 }
957 
958 void BM_editselection_plane(BMEditSelection *ese, float r_plane[3])
959 {
960  if (ese->htype == BM_VERT) {
961  BMVert *eve = (BMVert *)ese->ele;
962  float vec[3] = {0.0f, 0.0f, 0.0f};
963 
964  if (ese->prev) { /* use previously selected data to make a useful vertex plane */
965  BM_editselection_center(ese->prev, vec);
966  sub_v3_v3v3(r_plane, vec, eve->co);
967  }
968  else {
969  /* make a fake plane that's at right-angles to the normal
970  * we can't make a crossvec from a vec that's the same as the vec
971  * unlikely but possible, so make sure if the normal is (0, 0, 1)
972  * that vec isn't the same or in the same direction even. */
973  if (eve->no[0] < 0.5f) {
974  vec[0] = 1.0f;
975  }
976  else if (eve->no[1] < 0.5f) {
977  vec[1] = 1.0f;
978  }
979  else {
980  vec[2] = 1.0f;
981  }
982  cross_v3_v3v3(r_plane, eve->no, vec);
983  }
984  normalize_v3(r_plane);
985  }
986  else if (ese->htype == BM_EDGE) {
987  BMEdge *eed = (BMEdge *)ese->ele;
988 
989  if (BM_edge_is_boundary(eed)) {
990  sub_v3_v3v3(r_plane, eed->l->v->co, eed->l->next->v->co);
991  }
992  else {
993  /* the plane is simple, it runs along the edge
994  * however selecting different edges can swap the direction of the y axis.
995  * this makes it less likely for the y axis of the gizmo
996  * (running along the edge).. to flip less often.
997  * at least its more predictable */
998  if (eed->v2->co[1] > eed->v1->co[1]) { /* check which to do first */
999  sub_v3_v3v3(r_plane, eed->v2->co, eed->v1->co);
1000  }
1001  else {
1002  sub_v3_v3v3(r_plane, eed->v1->co, eed->v2->co);
1003  }
1004  }
1005 
1006  normalize_v3(r_plane);
1007  }
1008  else if (ese->htype == BM_FACE) {
1009  BMFace *efa = (BMFace *)ese->ele;
1010  BM_face_calc_tangent_auto(efa, r_plane);
1011  }
1012 }
1013 
1015 {
1017  "BMEdit Selection");
1018  ese->htype = ele->htype;
1019  ese->ele = (BMElem *)ele;
1020  return ese;
1021 }
1022 
1023 /* --- macro wrapped funcs --- */
1024 
1026 {
1027  return (BLI_findptr(&bm->selected, ele, offsetof(BMEditSelection, ele)) != NULL);
1028 }
1029 
1031 {
1032  BMEditSelection *ese = BLI_findptr(&bm->selected, ele, offsetof(BMEditSelection, ele));
1033  if (ese) {
1034  BLI_freelinkN(&bm->selected, ese);
1035  return true;
1036  }
1037  return false;
1038 }
1039 
1041 {
1043  BLI_addtail(&(bm->selected), ese);
1044 }
1045 
1047 {
1049  BLI_addhead(&(bm->selected), ese);
1050 }
1051 
1053 {
1054  if (!BM_select_history_check(bm, (BMElem *)ele)) {
1056  }
1057 }
1058 
1060 {
1061  if (!BM_select_history_check(bm, (BMElem *)ele)) {
1063  }
1064 }
1065 
1067 {
1069  BLI_insertlinkafter(&(bm->selected), ese_ref, ese);
1070 }
1071 
1073 {
1074  if (!BM_select_history_check(bm, (BMElem *)ele)) {
1076  }
1077 }
1078 /* --- end macro wrapped funcs --- */
1079 
1081 {
1083 }
1084 
1086 {
1087  BMEditSelection *ese, *ese_next;
1088 
1089  for (ese = bm->selected.first; ese; ese = ese_next) {
1090  ese_next = ese->next;
1091  if (!BM_elem_flag_test(ese->ele, BM_ELEM_SELECT)) {
1092  BLI_freelinkN(&(bm->selected), ese);
1093  }
1094  }
1095 }
1096 
1098 {
1099  BMEditSelection *ese_last = bm->selected.last;
1100  BMFace *efa = BM_mesh_active_face_get(bm, false, true);
1101 
1102  ese->next = ese->prev = NULL;
1103 
1104  if (ese_last) {
1105  /* If there is an active face, use it over the last selected face. */
1106  if (ese_last->htype == BM_FACE) {
1107  if (efa) {
1108  ese->ele = (BMElem *)efa;
1109  }
1110  else {
1111  ese->ele = ese_last->ele;
1112  }
1113  ese->htype = BM_FACE;
1114  }
1115  else {
1116  ese->ele = ese_last->ele;
1117  ese->htype = ese_last->htype;
1118  }
1119  }
1120  else if (efa) {
1121  /* no edit-selection, fallback to active face */
1122  ese->ele = (BMElem *)efa;
1123  ese->htype = BM_FACE;
1124  }
1125  else {
1126  ese->ele = NULL;
1127  return false;
1128  }
1129 
1130  return true;
1131 }
1132 
1134 {
1135  BMEditSelection *ese;
1136  GHash *map;
1137 
1139  return NULL;
1140  }
1141 
1142  map = BLI_ghash_ptr_new(__func__);
1143 
1144  for (ese = bm->selected.first; ese; ese = ese->next) {
1145  BLI_ghash_insert(map, ese->ele, ese);
1146  }
1147 
1148  return map;
1149 }
1150 
1152  BMesh *bm, GHash *vert_map, GHash *edge_map, GHash *face_map, const bool use_chain)
1153 {
1154 
1155 #ifdef DEBUG
1158  }
1159 #endif
1160 
1163 
1164  /* Only loop when (use_chain == true). */
1165  GHash *map = NULL;
1166  switch (ese->ele->head.htype) {
1167  case BM_VERT:
1168  map = vert_map;
1169  break;
1170  case BM_EDGE:
1171  map = edge_map;
1172  break;
1173  case BM_FACE:
1174  map = face_map;
1175  break;
1176  default:
1177  BMESH_ASSERT(0);
1178  break;
1179  }
1180  if (map != NULL) {
1181  BMElem *ele_dst = ese->ele;
1182  while (true) {
1183  BMElem *ele_dst_next = BLI_ghash_lookup(map, ele_dst);
1184  BLI_assert(ele_dst != ele_dst_next);
1185  if (ele_dst_next == NULL) {
1186  break;
1187  }
1188  ele_dst = ele_dst_next;
1189  /* Break loop on circular reference (should never happen). */
1190  if (UNLIKELY(ele_dst == ese->ele)) {
1191  BLI_assert(0);
1192  break;
1193  }
1194  if (use_chain == false) {
1195  break;
1196  }
1197  }
1198  ese->ele = ele_dst;
1199  }
1200  }
1201 
1202  /* Remove overlapping duplicates. */
1203  for (BMEditSelection *ese = bm->selected.first, *ese_next; ese; ese = ese_next) {
1204  ese_next = ese->next;
1205  if (BM_ELEM_API_FLAG_TEST(ese->ele, _FLAG_OVERLAP)) {
1207  }
1208  else {
1209  BLI_freelinkN(&bm->selected, ese);
1210  }
1211  }
1212 }
1213 
1215  const char htype,
1216  const char hflag,
1217  const bool respecthide,
1218  const bool overwrite,
1219  const char hflag_test)
1220 {
1221  const char iter_types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
1222 
1223  const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
1224 
1225  const char hflag_nosel = hflag & ~BM_ELEM_SELECT;
1226 
1227  int i;
1228 
1229  BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
1230 
1231  if (hflag & BM_ELEM_SELECT) {
1233  }
1234 
1235  if ((htype == (BM_VERT | BM_EDGE | BM_FACE)) && (hflag == BM_ELEM_SELECT) &&
1236  (respecthide == false) && (hflag_test == 0)) {
1237  /* fast path for deselect all, avoid topology loops
1238  * since we know all will be de-selected anyway. */
1239  for (i = 0; i < 3; i++) {
1240  BMIter iter;
1241  BMElem *ele;
1242 
1243  ele = BM_iter_new(&iter, bm, iter_types[i], NULL);
1244  for (; ele; ele = BM_iter_step(&iter)) {
1246  }
1247  }
1248 
1249  bm->totvertsel = bm->totedgesel = bm->totfacesel = 0;
1250  }
1251  else {
1252  for (i = 0; i < 3; i++) {
1253  BMIter iter;
1254  BMElem *ele;
1255 
1256  if (htype & flag_types[i]) {
1257  ele = BM_iter_new(&iter, bm, iter_types[i], NULL);
1258  for (; ele; ele = BM_iter_step(&iter)) {
1259 
1260  if (UNLIKELY(respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN))) {
1261  /* pass */
1262  }
1263  else if (!hflag_test || BM_elem_flag_test(ele, hflag_test)) {
1264  if (hflag & BM_ELEM_SELECT) {
1265  BM_elem_select_set(bm, ele, false);
1266  }
1267  BM_elem_flag_disable(ele, hflag);
1268  }
1269  else if (overwrite) {
1270  /* no match! */
1271  if (hflag & BM_ELEM_SELECT) {
1272  BM_elem_select_set(bm, ele, true);
1273  }
1274  BM_elem_flag_enable(ele, hflag_nosel);
1275  }
1276  }
1277  }
1278  }
1279  }
1280 }
1281 
1283  const char htype,
1284  const char hflag,
1285  const bool respecthide,
1286  const bool overwrite,
1287  const char hflag_test)
1288 {
1289  const char iter_types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
1290 
1291  const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
1292 
1293  /* use the nosel version when setting so under no
1294  * condition may a hidden face become selected.
1295  * Applying other flags to hidden faces is OK. */
1296  const char hflag_nosel = hflag & ~BM_ELEM_SELECT;
1297 
1298  BMIter iter;
1299  BMElem *ele;
1300  int i;
1301 
1302  BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
1303 
1304  /* NOTE: better not attempt a fast path for selection as done with de-select
1305  * because hidden geometry and different selection modes can give different results,
1306  * we could of course check for no hidden faces and then use
1307  * quicker method but its not worth it. */
1308 
1309  for (i = 0; i < 3; i++) {
1310  if (htype & flag_types[i]) {
1311  ele = BM_iter_new(&iter, bm, iter_types[i], NULL);
1312  for (; ele; ele = BM_iter_step(&iter)) {
1313 
1314  if (UNLIKELY(respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN))) {
1315  /* pass */
1316  }
1317  else if (!hflag_test || BM_elem_flag_test(ele, hflag_test)) {
1318  /* match! */
1319  if (hflag & BM_ELEM_SELECT) {
1320  BM_elem_select_set(bm, ele, true);
1321  }
1322  BM_elem_flag_enable(ele, hflag_nosel);
1323  }
1324  else if (overwrite) {
1325  /* no match! */
1326  if (hflag & BM_ELEM_SELECT) {
1327  BM_elem_select_set(bm, ele, false);
1328  }
1329  BM_elem_flag_disable(ele, hflag);
1330  }
1331  }
1332  }
1333  }
1334 }
1335 
1337  const char htype,
1338  const char hflag,
1339  const bool respecthide)
1340 {
1341  /* call with 0 hflag_test */
1342  BM_mesh_elem_hflag_disable_test(bm, htype, hflag, respecthide, false, 0);
1343 }
1344 
1346  const char htype,
1347  const char hflag,
1348  const bool respecthide)
1349 {
1350  /* call with 0 hflag_test */
1351  BM_mesh_elem_hflag_enable_test(bm, htype, hflag, respecthide, false, 0);
1352 }
1353 
1354 /***************** Mesh Hiding stuff *********** */
1355 
1361 {
1363 }
1364 
1370 {
1372 }
1373 
1374 void BM_vert_hide_set(BMVert *v, const bool hide)
1375 {
1376  /* vert hiding: vert + surrounding edges and faces */
1377  BLI_assert(v->head.htype == BM_VERT);
1378  if (hide) {
1380  }
1381 
1383 
1384  if (v->e) {
1385  BMEdge *e_iter, *e_first;
1386  e_iter = e_first = v->e;
1387  do {
1388  BM_elem_flag_set(e_iter, BM_ELEM_HIDDEN, hide);
1389  if (e_iter->l) {
1390  const BMLoop *l_radial_iter, *l_radial_first;
1391  l_radial_iter = l_radial_first = e_iter->l;
1392  do {
1393  BM_elem_flag_set(l_radial_iter->f, BM_ELEM_HIDDEN, hide);
1394  } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
1395  }
1396  } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
1397  }
1398 }
1399 
1400 void BM_edge_hide_set(BMEdge *e, const bool hide)
1401 {
1402  BLI_assert(e->head.htype == BM_EDGE);
1403  if (hide) {
1405  }
1406 
1407  /* edge hiding: faces around the edge */
1408  if (e->l) {
1409  const BMLoop *l_iter, *l_first;
1410  l_iter = l_first = e->l;
1411  do {
1412  BM_elem_flag_set(l_iter->f, BM_ELEM_HIDDEN, hide);
1413  } while ((l_iter = l_iter->radial_next) != l_first);
1414  }
1415 
1417 
1418  /* hide vertices if necessary */
1419  if (hide) {
1420  vert_flush_hide_set(e->v1);
1421  vert_flush_hide_set(e->v2);
1422  }
1423  else {
1426  }
1427 }
1428 
1429 void BM_face_hide_set(BMFace *f, const bool hide)
1430 {
1431  BLI_assert(f->head.htype == BM_FACE);
1432  if (hide) {
1434  }
1435 
1436  BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide);
1437 
1438  if (hide) {
1439  BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
1440  BMLoop *l_iter;
1441 
1442  l_iter = l_first;
1443  do {
1444  edge_flush_hide_set(l_iter->e);
1445  } while ((l_iter = l_iter->next) != l_first);
1446 
1447  l_iter = l_first;
1448  do {
1449  vert_flush_hide_set(l_iter->v);
1450  } while ((l_iter = l_iter->next) != l_first);
1451  }
1452  else {
1453  BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
1454  BMLoop *l_iter;
1455 
1456  l_iter = l_first;
1457  do {
1460  } while ((l_iter = l_iter->next) != l_first);
1461  }
1462 }
1463 
1464 void _bm_elem_hide_set(BMesh *bm, BMHeader *head, const bool hide)
1465 {
1466  /* Follow convention of always deselecting before
1467  * hiding an element */
1468  switch (head->htype) {
1469  case BM_VERT:
1470  if (hide) {
1471  BM_vert_select_set(bm, (BMVert *)head, false);
1472  }
1473  BM_vert_hide_set((BMVert *)head, hide);
1474  break;
1475  case BM_EDGE:
1476  if (hide) {
1477  BM_edge_select_set(bm, (BMEdge *)head, false);
1478  }
1479  BM_edge_hide_set((BMEdge *)head, hide);
1480  break;
1481  case BM_FACE:
1482  if (hide) {
1483  BM_face_select_set(bm, (BMFace *)head, false);
1484  }
1485  BM_face_hide_set((BMFace *)head, hide);
1486  break;
1487  default:
1488  BMESH_ASSERT(0);
1489  break;
1490  }
1491 }
#define BLI_assert(a)
Definition: BLI_assert.h:46
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:734
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:710
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:269
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:60
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:239
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:301
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:466
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
void * BLI_findptr(const struct ListBase *listbase, const void *ptr, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE float normalize_v3(float r[3])
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])
Definition: math_vector.c:237
struct MempoolIterData MempoolIterData
Definition: BLI_task.h:272
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition: BLI_task.h:293
void(* TaskParallelMempoolFunc)(void *userdata, MempoolIterData *iter, const TaskParallelTLS *__restrict tls)
Definition: BLI_task.h:274
#define UNUSED(x)
#define UNLIKELY(x)
#define ELEM(...)
#define SCE_SELECT_FACE
#define SCE_SELECT_VERTEX
#define SCE_SELECT_EDGE
Read Guarded memory(de)allocation.
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: avxb.h:154
#define BM_ALL_NOLOOP
Definition: bmesh_class.h:411
#define BM_OMP_LIMIT
Definition: bmesh_class.h:656
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:622
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_EDGE
Definition: bmesh_class.h:384
@ BM_ELEM_HIDDEN
Definition: bmesh_class.h:472
@ BM_ELEM_SELECT
Definition: bmesh_class.h:471
#define BMESH_ASSERT(a)
Definition: bmesh_error.h:80
#define BM_elem_flag_disable(ele, hflag)
Definition: bmesh_inline.h:15
#define BM_elem_flag_set(ele, hflag, val)
Definition: bmesh_inline.h:16
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:12
#define BM_elem_flag_test_bool(ele, hflag)
Definition: bmesh_inline.h:13
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:14
#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)
ATTR_WARN_UNUSED_RESULT BMesh * bm
static TaskParallelMempoolFunc recount_totsels_get_range_func(BMIterType iter_type)
Definition: bmesh_marking.c:80
void BM_select_history_clear(BMesh *bm)
static void bm_mesh_select_mode_flush_reduce_fn(const void *__restrict UNUSED(userdata), void *__restrict chunk_join, void *__restrict chunk)
BMEdge * BM_mesh_active_edge_get(BMesh *bm)
static void vert_flush_hide_set(BMVert *v)
struct SelectionCountChunkData SelectionCountChunkData
void _bm_elem_hide_set(BMesh *bm, BMHeader *head, const bool hide)
struct SelectionFlushChunkData SelectionFlushChunkData
bool _bm_select_history_check(BMesh *bm, const BMHeader *ele)
void _bm_select_history_store_head_notest(BMesh *bm, BMHeader *ele)
static void recount_totsels_range_face_func(void *UNUSED(userdata), MempoolIterData *iter, const TaskParallelTLS *__restrict tls)
Definition: bmesh_marking.c:60
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)
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)
void BM_mesh_select_mode_set(BMesh *bm, int selectmode)
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)
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)
static void recount_totsels_reduce(const void *__restrict UNUSED(userdata), void *__restrict chunk_join, void *__restrict chunk)
Definition: bmesh_marking.c:71
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)
static void recount_totsels_range_vert_func(void *UNUSED(userdata), MempoolIterData *iter, const TaskParallelTLS *__restrict tls)
Definition: bmesh_marking.c:38
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 BMEditSelection * bm_select_history_create(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)
GHash * BM_select_history_map_create(BMesh *bm)
static int recount_totsel(BMesh *bm, BMIterType iter_type)
Definition: bmesh_marking.c:97
static void recount_totsels_range_edge_func(void *UNUSED(userdata), MempoolIterData *iter, const TaskParallelTLS *__restrict tls)
Definition: bmesh_marking.c:49
void BM_mesh_select_mode_clean(BMesh *bm)
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])
void BM_mesh_deselect_flush(BMesh *bm)
static void edge_flush_hide_set(BMEdge *e)
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)
BMVert * BM_mesh_active_vert_get(BMesh *bm)
static void bm_mesh_select_mode_flush_vert_to_edge_iter_fn(void *UNUSED(userdata), MempoolIterData *iter, const TaskParallelTLS *__restrict tls)
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)
BMFace * BM_mesh_active_face_get(BMesh *bm, const bool is_sloppy, const bool is_selected)
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 recount_totedgesel(BMesh *bm)
bool BM_select_history_active_get(BMesh *bm, BMEditSelection *ese)
static void bm_mesh_select_mode_flush_edge_to_face_iter_fn(void *UNUSED(userdata), MempoolIterData *iter, const TaskParallelTLS *__restrict tls)
void BM_face_hide_set(BMFace *f, const bool hide)
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)
BMElem * BM_mesh_active_elem_get(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
Definition: bmesh_marking.h:15
@ BM_SELECT_LEN_FLUSH_RECALC_ALL
Definition: bmesh_marking.h:20
@ BM_SELECT_LEN_FLUSH_RECALC_EDGE
Definition: bmesh_marking.h:18
@ BM_SELECT_LEN_FLUSH_RECALC_FACE
Definition: bmesh_marking.h:19
@ BM_SELECT_LEN_FLUSH_RECALC_VERT
Definition: bmesh_marking.h:17
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])
@ _FLAG_OVERLAP
Definition: bmesh_private.h:59
#define BM_ELEM_API_FLAG_DISABLE(element, f)
Definition: bmesh_private.h:71
#define BM_ELEM_API_FLAG_TEST(element, f)
Definition: bmesh_private.h:76
#define BM_ELEM_API_FLAG_ENABLE(element, f)
Definition: bmesh_private.h:66
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()
SyclQueue void void * src
int count
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
SocketIndexByIdentifierMap * map
BMVert * v1
Definition: bmesh_class.h:122
BMVert * v2
Definition: bmesh_class.h:122
struct BMLoop * l
Definition: bmesh_class.h:128
struct BMEditSelection * next
Definition: bmesh_marking.h:10
struct BMEditSelection * prev
Definition: bmesh_marking.h:10
BMHeader head
Definition: bmesh_class.h:243
BMHeader head
Definition: bmesh_class.h:255
float no[3]
Definition: bmesh_class.h:271
char htype
Definition: bmesh_class.h:64
struct BMVert * v
Definition: bmesh_class.h:153
struct BMEdge * e
Definition: bmesh_class.h:164
struct BMLoop * radial_next
Definition: bmesh_class.h:204
struct BMFace * f
Definition: bmesh_class.h:171
struct BMLoop * next
Definition: bmesh_class.h:233
float co[3]
Definition: bmesh_class.h:87
struct BMEdge * e
Definition: bmesh_class.h:97
float no[3]
Definition: bmesh_class.h:88
BMHeader head
Definition: bmesh_class.h:85
int totfacesel
Definition: bmesh_class.h:298
int totedge
Definition: bmesh_class.h:297
ListBase selected
Definition: bmesh_class.h:356
int totvertsel
Definition: bmesh_class.h:298
BMFace * act_face
Definition: bmesh_class.h:366
short selectmode
Definition: bmesh_class.h:350
int totedgesel
Definition: bmesh_class.h:298
int totface
Definition: bmesh_class.h:297
void * last
Definition: DNA_listBase.h:31
void * first
Definition: DNA_listBase.h:31
TaskParallelReduceFunc func_reduce
Definition: BLI_task.h:181
size_t userdata_chunk_size
Definition: BLI_task.h:169