Blender  V2.93
bmesh_marking.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
28 #include <stddef.h>
29 
30 #include "MEM_guardedalloc.h"
31 
32 #include "DNA_scene_types.h"
33 
34 #include "BLI_listbase.h"
35 #include "BLI_math.h"
36 
37 #include "bmesh.h"
38 #include "bmesh_structure.h"
39 
40 /* For '_FLAG_OVERLAP'. */
41 #include "bmesh_private.h"
42 
43 static void recount_totsels(BMesh *bm)
44 {
45  const char iter_types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
46  int *tots[3];
47  int i;
48 
49  /* Recount total selection variables. */
51  tots[0] = &bm->totvertsel;
52  tots[1] = &bm->totedgesel;
53  tots[2] = &bm->totfacesel;
54 
55  for (i = 0; i < 3; i++) {
56  BMIter iter;
57  BMElem *ele;
58  int count = 0;
59 
60  BM_ITER_MESH (ele, &iter, bm, iter_types[i]) {
62  count += 1;
63  }
64  }
65  *tots[i] = count;
66  }
67 }
68 
69 /* -------------------------------------------------------------------- */
73 static bool bm_vert_is_edge_select_any_other(const BMVert *v, const BMEdge *e_first)
74 {
75  const BMEdge *e_iter = e_first;
76 
77  /* start by stepping over the current edge */
78  while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first) {
79  if (BM_elem_flag_test(e_iter, BM_ELEM_SELECT)) {
80  return true;
81  }
82  }
83  return false;
84 }
85 
86 #if 0
87 static bool bm_vert_is_edge_select_any(const BMVert *v)
88 {
89  if (v->e) {
90  const BMEdge *e_iter, *e_first;
91  e_iter = e_first = v->e;
92  do {
93  if (BM_elem_flag_test(e_iter, BM_ELEM_SELECT)) {
94  return true;
95  }
96  } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
97  }
98  return false;
99 }
100 #endif
101 
103 {
104  if (v->e) {
105  const BMEdge *e_iter, *e_first;
106  e_iter = e_first = v->e;
107  do {
108  if (!BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN)) {
109  return true;
110  }
111  } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
112  }
113  return false;
114 }
115 
117 {
118  const BMLoop *l_iter = l_first;
119 
120  /* start by stepping over the current face */
121  while ((l_iter = l_iter->radial_next) != l_first) {
122  if (BM_elem_flag_test(l_iter->f, BM_ELEM_SELECT)) {
123  return true;
124  }
125  }
126  return false;
127 }
128 
129 #if 0
130 static bool bm_edge_is_face_select_any(const BMEdge *e)
131 {
132  if (e->l) {
133  const BMLoop *l_iter, *l_first;
134  l_iter = l_first = e->l;
135  do {
136  if (BM_elem_flag_test(l_iter->f, BM_ELEM_SELECT)) {
137  return true;
138  }
139  } while ((l_iter = l_iter->radial_next) != l_first);
140  }
141  return false;
142 }
143 #endif
144 
146 {
147  if (e->l) {
148  const BMLoop *l_iter, *l_first;
149  l_iter = l_first = e->l;
150  do {
151  if (!BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
152  return true;
153  }
154  } while ((l_iter = l_iter->radial_next) != l_first);
155  }
156  return false;
157 }
158 
169 void BM_mesh_select_mode_clean_ex(BMesh *bm, const short selectmode)
170 {
171  if (selectmode & SCE_SELECT_VERTEX) {
172  /* pass */
173  }
174  else if (selectmode & SCE_SELECT_EDGE) {
175  BMIter iter;
176 
177  if (bm->totvertsel) {
178  BMVert *v;
179  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
181  }
182  bm->totvertsel = 0;
183  }
184 
185  if (bm->totedgesel) {
186  BMEdge *e;
187  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
189  BM_vert_select_set(bm, e->v1, true);
190  BM_vert_select_set(bm, e->v2, true);
191  }
192  }
193  }
194  }
195  else if (selectmode & SCE_SELECT_FACE) {
196  BMIter iter;
197 
198  if (bm->totvertsel) {
199  BMVert *v;
200  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
202  }
203  bm->totvertsel = 0;
204  }
205 
206  if (bm->totedgesel) {
207  BMEdge *e;
208  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
210  }
211  bm->totedgesel = 0;
212  }
213 
214  if (bm->totfacesel) {
215  BMFace *f;
216  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
218  BMLoop *l_iter, *l_first;
219  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
220  do {
221  BM_edge_select_set(bm, l_iter->e, true);
222  } while ((l_iter = l_iter->next) != l_first);
223  }
224  }
225  }
226  }
227 }
228 
230 {
232 }
233 
241 void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode)
242 {
243  BMEdge *e;
244  BMLoop *l_iter;
245  BMLoop *l_first;
246  BMFace *f;
247 
248  BMIter eiter;
249  BMIter fiter;
250 
251  if (selectmode & SCE_SELECT_VERTEX) {
252  /* both loops only set edge/face flags and read off verts */
253  BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
257  }
258  else {
260  }
261  }
262  BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
263  bool ok = true;
265  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
266  do {
267  if (!BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
268  ok = false;
269  break;
270  }
271  } while ((l_iter = l_iter->next) != l_first);
272  }
273  else {
274  ok = false;
275  }
276 
278  }
279  }
280  else if (selectmode & SCE_SELECT_EDGE) {
281  BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
282  bool ok = true;
284  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
285  do {
286  if (!BM_elem_flag_test(l_iter->e, BM_ELEM_SELECT)) {
287  ok = false;
288  break;
289  }
290  } while ((l_iter = l_iter->next) != l_first);
291  }
292  else {
293  ok = false;
294  }
295 
297  }
298  }
299 
300  /* Remove any deselected elements from the BMEditSelection */
302 
304 }
305 
307 {
309 }
310 
315 {
316  BMIter eiter;
317  BMEdge *e;
318 
319  BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
322  if (!BM_elem_flag_test(e->v1, BM_ELEM_SELECT) ||
325  }
326  }
327 
328  if (e->l && !BM_elem_flag_test(e, BM_ELEM_SELECT)) {
329  BMLoop *l_iter;
330  BMLoop *l_first;
331 
332  l_iter = l_first = e->l;
333  do {
335  } while ((l_iter = l_iter->radial_next) != l_first);
336  }
337  }
338  }
339 
340  /* Remove any deselected elements from the BMEditSelection */
342 
344 }
345 
350 {
351  BMEdge *e;
352  BMLoop *l_iter;
353  BMLoop *l_first;
354  BMFace *f;
355 
356  BMIter eiter;
357  BMIter fiter;
358 
359  bool ok;
360 
361  BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
365  }
366  }
367  BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
368  ok = true;
370  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
371  do {
372  if (!BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
373  ok = false;
374  break;
375  }
376  } while ((l_iter = l_iter->next) != l_first);
377  }
378  else {
379  ok = false;
380  }
381 
382  if (ok) {
384  }
385  }
386 
388 }
389 
396 void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
397 {
399 
401  return;
402  }
403 
404  if (select) {
407  bm->totvertsel += 1;
408  }
409  }
410  else {
412  bm->totvertsel -= 1;
414  }
415  }
416 }
417 
423 void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
424 {
426 
428  return;
429  }
430 
431  if (select) {
434  bm->totedgesel += 1;
435  }
436  BM_vert_select_set(bm, e->v1, true);
437  BM_vert_select_set(bm, e->v2, true);
438  }
439  else {
442  bm->totedgesel -= 1;
443  }
444 
445  if ((bm->selectmode & SCE_SELECT_VERTEX) == 0) {
446  int i;
447 
448  /* check if the vert is used by a selected edge */
449  for (i = 0; i < 2; i++) {
450  BMVert *v = *((&e->v1) + i);
451  if (bm_vert_is_edge_select_any_other(v, e) == false) {
452  BM_vert_select_set(bm, v, false);
453  }
454  }
455  }
456  else {
457  BM_vert_select_set(bm, e->v1, false);
458  BM_vert_select_set(bm, e->v2, false);
459  }
460  }
461 }
462 
469 void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
470 {
471  BMLoop *l_iter;
472  BMLoop *l_first;
473 
474  BLI_assert(f->head.htype == BM_FACE);
475 
477  return;
478  }
479 
480  if (select) {
483  bm->totfacesel += 1;
484  }
485 
486  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
487  do {
488  BM_vert_select_set(bm, l_iter->v, true);
489  BM_edge_select_set(bm, l_iter->e, true);
490  } while ((l_iter = l_iter->next) != l_first);
491  }
492  else {
493 
496  bm->totfacesel -= 1;
497  }
507  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
508  do {
509  BM_vert_select_set(bm, l_iter->v, false);
510  BM_edge_select_set_noflush(bm, l_iter->e, false);
511  } while ((l_iter = l_iter->next) != l_first);
512  }
513  else {
518  if (bm->selectmode & SCE_SELECT_EDGE) {
519  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
520  do {
521  BM_edge_select_set_noflush(bm, l_iter->e, false);
522  } while ((l_iter = l_iter->next) != l_first);
523  }
524  else {
525  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
526  do {
527  if (bm_edge_is_face_select_any_other(l_iter) == false) {
528  BM_edge_select_set_noflush(bm, l_iter->e, false);
529  }
530  } while ((l_iter = l_iter->next) != l_first);
531  }
532 
533  /* flush down to verts */
534  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
535  do {
536  if (bm_vert_is_edge_select_any_other(l_iter->v, l_iter->e) == false) {
537  BM_vert_select_set(bm, l_iter->v, false);
538  }
539  } while ((l_iter = l_iter->next) != l_first);
540  }
541  }
542 }
543 
544 /* -------------------------------------------------------------------- */
549 {
551 
553  return;
554  }
555 
556  if (select) {
559  bm->totedgesel += 1;
560  }
561  }
562  else {
565  bm->totedgesel -= 1;
566  }
567  }
568 }
569 
571 {
572  BLI_assert(f->head.htype == BM_FACE);
573 
575  return;
576  }
577 
578  if (select) {
581  bm->totfacesel += 1;
582  }
583  }
584  else {
587  bm->totfacesel -= 1;
588  }
589  }
590 }
591 
600 void BM_mesh_select_mode_set(BMesh *bm, int selectmode)
601 {
602  BMIter iter;
603  BMElem *ele;
604 
605  bm->selectmode = selectmode;
606 
608  /* disabled because selection flushing handles these */
609 #if 0
610  BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
612  }
613  BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
615  }
616 #endif
618  }
619  else if (bm->selectmode & SCE_SELECT_EDGE) {
620  /* disabled because selection flushing handles these */
621 #if 0
622  BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
624  }
625 #endif
626 
627  BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
628  if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
629  BM_edge_select_set(bm, (BMEdge *)ele, true);
630  }
631  }
633  }
634  else if (bm->selectmode & SCE_SELECT_FACE) {
635  /* disabled because selection flushing handles these */
636 #if 0
637  BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
639  }
640 #endif
641  BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
642  if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
643  BM_face_select_set(bm, (BMFace *)ele, true);
644  }
645  }
647  }
648 }
649 
654  const char htype,
655  const char hflag,
656  const bool respecthide,
657  const bool test_for_enabled)
658 {
659  BMElem *ele;
660  BMIter iter;
661  int tot = 0;
662 
663  BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
664 
665  if (htype & BM_VERT) {
666  BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
667  if (respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) {
668  continue;
669  }
670  if (BM_elem_flag_test_bool(ele, hflag) == test_for_enabled) {
671  tot++;
672  }
673  }
674  }
675  if (htype & BM_EDGE) {
676  BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
677  if (respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) {
678  continue;
679  }
680  if (BM_elem_flag_test_bool(ele, hflag) == test_for_enabled) {
681  tot++;
682  }
683  }
684  }
685  if (htype & BM_FACE) {
686  BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
687  if (respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) {
688  continue;
689  }
690  if (BM_elem_flag_test_bool(ele, hflag) == test_for_enabled) {
691  tot++;
692  }
693  }
694  }
695 
696  return tot;
697 }
698 
700  const char htype,
701  const char hflag,
702  const bool respecthide)
703 {
704  return bm_mesh_flag_count(bm, htype, hflag, respecthide, true);
705 }
706 
708  const char htype,
709  const char hflag,
710  const bool respecthide)
711 {
712  return bm_mesh_flag_count(bm, htype, hflag, respecthide, false);
713 }
714 
719 void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select)
720 {
721  switch (ele->head.htype) {
722  case BM_VERT:
724  break;
725  case BM_EDGE:
727  break;
728  case BM_FACE:
730  break;
731  default:
732  BLI_assert(0);
733  break;
734  }
735 }
736 
737 /* this replaces the active flag used in uv/face mode */
739 {
740  bm->act_face = f;
741 }
742 
743 BMFace *BM_mesh_active_face_get(BMesh *bm, const bool is_sloppy, const bool is_selected)
744 {
745  if (bm->act_face && (!is_selected || BM_elem_flag_test(bm->act_face, BM_ELEM_SELECT))) {
746  return bm->act_face;
747  }
748  if (is_sloppy) {
749  BMIter iter;
750  BMFace *f = NULL;
751  BMEditSelection *ese;
752 
753  /* Find the latest non-hidden face from the BMEditSelection */
754  ese = bm->selected.last;
755  for (; ese; ese = ese->prev) {
756  if (ese->htype == BM_FACE) {
757  f = (BMFace *)ese->ele;
758 
760  f = NULL;
761  }
762  else if (is_selected && !BM_elem_flag_test(f, BM_ELEM_SELECT)) {
763  f = NULL;
764  }
765  else {
766  break;
767  }
768  }
769  }
770  /* Last attempt: try to find any selected face */
771  if (f == NULL) {
772  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
774  break;
775  }
776  }
777  }
778  return f; /* can still be null */
779  }
780  return NULL;
781 }
782 
784 {
785  if (bm->selected.last) {
787 
788  if (ese && ese->htype == BM_EDGE) {
789  return (BMEdge *)ese->ele;
790  }
791  }
792 
793  return NULL;
794 }
795 
797 {
798  if (bm->selected.last) {
800 
801  if (ese && ese->htype == BM_VERT) {
802  return (BMVert *)ese->ele;
803  }
804  }
805 
806  return NULL;
807 }
808 
810 {
811  if (bm->selected.last) {
813 
814  if (ese) {
815  return ese->ele;
816  }
817  }
818 
819  return NULL;
820 }
821 
831 void BM_editselection_center(BMEditSelection *ese, float r_center[3])
832 {
833  if (ese->htype == BM_VERT) {
834  BMVert *eve = (BMVert *)ese->ele;
835  copy_v3_v3(r_center, eve->co);
836  }
837  else if (ese->htype == BM_EDGE) {
838  BMEdge *eed = (BMEdge *)ese->ele;
839  mid_v3_v3v3(r_center, eed->v1->co, eed->v2->co);
840  }
841  else if (ese->htype == BM_FACE) {
842  BMFace *efa = (BMFace *)ese->ele;
843  BM_face_calc_center_median(efa, r_center);
844  }
845 }
846 
847 void BM_editselection_normal(BMEditSelection *ese, float r_normal[3])
848 {
849  if (ese->htype == BM_VERT) {
850  BMVert *eve = (BMVert *)ese->ele;
851  copy_v3_v3(r_normal, eve->no);
852  }
853  else if (ese->htype == BM_EDGE) {
854  BMEdge *eed = (BMEdge *)ese->ele;
855  float plane[3]; /* need a plane to correct the normal */
856  float vec[3]; /* temp vec storage */
857 
858  add_v3_v3v3(r_normal, eed->v1->no, eed->v2->no);
859  sub_v3_v3v3(plane, eed->v2->co, eed->v1->co);
860 
861  /* the 2 vertex normals will be close but not at right angles to the edge
862  * for rotate about edge we want them to be at right angles, so we need to
863  * do some extra calculation to correct the vert normals,
864  * we need the plane for this */
865  cross_v3_v3v3(vec, r_normal, plane);
866  cross_v3_v3v3(r_normal, plane, vec);
867  normalize_v3(r_normal);
868  }
869  else if (ese->htype == BM_FACE) {
870  BMFace *efa = (BMFace *)ese->ele;
871  copy_v3_v3(r_normal, efa->no);
872  }
873 }
874 
880 void BM_editselection_plane(BMEditSelection *ese, float r_plane[3])
881 {
882  if (ese->htype == BM_VERT) {
883  BMVert *eve = (BMVert *)ese->ele;
884  float vec[3] = {0.0f, 0.0f, 0.0f};
885 
886  if (ese->prev) { /* use previously selected data to make a useful vertex plane */
887  BM_editselection_center(ese->prev, vec);
888  sub_v3_v3v3(r_plane, vec, eve->co);
889  }
890  else {
891  /* make a fake plane that's at right-angles to the normal
892  * we can't make a crossvec from a vec that's the same as the vec
893  * unlikely but possible, so make sure if the normal is (0, 0, 1)
894  * that vec isn't the same or in the same direction even. */
895  if (eve->no[0] < 0.5f) {
896  vec[0] = 1.0f;
897  }
898  else if (eve->no[1] < 0.5f) {
899  vec[1] = 1.0f;
900  }
901  else {
902  vec[2] = 1.0f;
903  }
904  cross_v3_v3v3(r_plane, eve->no, vec);
905  }
906  normalize_v3(r_plane);
907  }
908  else if (ese->htype == BM_EDGE) {
909  BMEdge *eed = (BMEdge *)ese->ele;
910 
911  if (BM_edge_is_boundary(eed)) {
912  sub_v3_v3v3(r_plane, eed->l->v->co, eed->l->next->v->co);
913  }
914  else {
915  /* the plane is simple, it runs along the edge
916  * however selecting different edges can swap the direction of the y axis.
917  * this makes it less likely for the y axis of the gizmo
918  * (running along the edge).. to flip less often.
919  * at least its more predictable */
920  if (eed->v2->co[1] > eed->v1->co[1]) { /* check which to do first */
921  sub_v3_v3v3(r_plane, eed->v2->co, eed->v1->co);
922  }
923  else {
924  sub_v3_v3v3(r_plane, eed->v1->co, eed->v2->co);
925  }
926  }
927 
928  normalize_v3(r_plane);
929  }
930  else if (ese->htype == BM_FACE) {
931  BMFace *efa = (BMFace *)ese->ele;
932  BM_face_calc_tangent_auto(efa, r_plane);
933  }
934 }
935 
937 {
939  "BMEdit Selection");
940  ese->htype = ele->htype;
941  ese->ele = (BMElem *)ele;
942  return ese;
943 }
944 
945 /* --- macro wrapped funcs --- */
947 {
948  return (BLI_findptr(&bm->selected, ele, offsetof(BMEditSelection, ele)) != NULL);
949 }
950 
952 {
953  BMEditSelection *ese = BLI_findptr(&bm->selected, ele, offsetof(BMEditSelection, ele));
954  if (ese) {
955  BLI_freelinkN(&bm->selected, ese);
956  return true;
957  }
958  return false;
959 }
960 
962 {
964  BLI_addtail(&(bm->selected), ese);
965 }
966 
968 {
970  BLI_addhead(&(bm->selected), ese);
971 }
972 
974 {
975  if (!BM_select_history_check(bm, (BMElem *)ele)) {
977  }
978 }
979 
981 {
982  if (!BM_select_history_check(bm, (BMElem *)ele)) {
984  }
985 }
986 
988 {
990  BLI_insertlinkafter(&(bm->selected), ese_ref, ese);
991 }
992 
994 {
995  if (!BM_select_history_check(bm, (BMElem *)ele)) {
997  }
998 }
999 /* --- end macro wrapped funcs --- */
1000 
1002 {
1004 }
1005 
1007 {
1008  BMEditSelection *ese, *ese_next;
1009 
1010  for (ese = bm->selected.first; ese; ese = ese_next) {
1011  ese_next = ese->next;
1012  if (!BM_elem_flag_test(ese->ele, BM_ELEM_SELECT)) {
1013  BLI_freelinkN(&(bm->selected), ese);
1014  }
1015  }
1016 }
1017 
1022 {
1023  BMEditSelection *ese_last = bm->selected.last;
1024  BMFace *efa = BM_mesh_active_face_get(bm, false, true);
1025 
1026  ese->next = ese->prev = NULL;
1027 
1028  if (ese_last) {
1029  /* If there is an active face, use it over the last selected face. */
1030  if (ese_last->htype == BM_FACE) {
1031  if (efa) {
1032  ese->ele = (BMElem *)efa;
1033  }
1034  else {
1035  ese->ele = ese_last->ele;
1036  }
1037  ese->htype = BM_FACE;
1038  }
1039  else {
1040  ese->ele = ese_last->ele;
1041  ese->htype = ese_last->htype;
1042  }
1043  }
1044  else if (efa) {
1045  /* no edit-selection, fallback to active face */
1046  ese->ele = (BMElem *)efa;
1047  ese->htype = BM_FACE;
1048  }
1049  else {
1050  ese->ele = NULL;
1051  return false;
1052  }
1053 
1054  return true;
1055 }
1056 
1061 {
1062  BMEditSelection *ese;
1063  GHash *map;
1064 
1066  return NULL;
1067  }
1068 
1069  map = BLI_ghash_ptr_new(__func__);
1070 
1071  for (ese = bm->selected.first; ese; ese = ese->next) {
1072  BLI_ghash_insert(map, ese->ele, ese);
1073  }
1074 
1075  return map;
1076 }
1077 
1082  BMesh *bm, GHash *vert_map, GHash *edge_map, GHash *face_map, const bool use_chain)
1083 {
1084 
1085 #ifdef DEBUG
1088  }
1089 #endif
1090 
1093 
1094  /* Only loop when (use_chain == true). */
1095  GHash *map = NULL;
1096  switch (ese->ele->head.htype) {
1097  case BM_VERT:
1098  map = vert_map;
1099  break;
1100  case BM_EDGE:
1101  map = edge_map;
1102  break;
1103  case BM_FACE:
1104  map = face_map;
1105  break;
1106  default:
1107  BMESH_ASSERT(0);
1108  break;
1109  }
1110  if (map != NULL) {
1111  BMElem *ele_dst = ese->ele;
1112  while (true) {
1113  BMElem *ele_dst_next = BLI_ghash_lookup(map, ele_dst);
1114  BLI_assert(ele_dst != ele_dst_next);
1115  if (ele_dst_next == NULL) {
1116  break;
1117  }
1118  ele_dst = ele_dst_next;
1119  /* Break loop on circular reference (should never happen). */
1120  if (UNLIKELY(ele_dst == ese->ele)) {
1121  BLI_assert(0);
1122  break;
1123  }
1124  if (use_chain == false) {
1125  break;
1126  }
1127  }
1128  ese->ele = ele_dst;
1129  }
1130  }
1131 
1132  /* Remove overlapping duplicates. */
1133  for (BMEditSelection *ese = bm->selected.first, *ese_next; ese; ese = ese_next) {
1134  ese_next = ese->next;
1135  if (BM_ELEM_API_FLAG_TEST(ese->ele, _FLAG_OVERLAP)) {
1137  }
1138  else {
1139  BLI_freelinkN(&bm->selected, ese);
1140  }
1141  }
1142 }
1143 
1145  const char htype,
1146  const char hflag,
1147  const bool respecthide,
1148  const bool overwrite,
1149  const char hflag_test)
1150 {
1151  const char iter_types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
1152 
1153  const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
1154 
1155  const char hflag_nosel = hflag & ~BM_ELEM_SELECT;
1156 
1157  int i;
1158 
1159  BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
1160 
1161  if (hflag & BM_ELEM_SELECT) {
1163  }
1164 
1165  if ((htype == (BM_VERT | BM_EDGE | BM_FACE)) && (hflag == BM_ELEM_SELECT) &&
1166  (respecthide == false) && (hflag_test == 0)) {
1167  /* fast path for deselect all, avoid topology loops
1168  * since we know all will be de-selected anyway. */
1169  for (i = 0; i < 3; i++) {
1170  BMIter iter;
1171  BMElem *ele;
1172 
1173  ele = BM_iter_new(&iter, bm, iter_types[i], NULL);
1174  for (; ele; ele = BM_iter_step(&iter)) {
1176  }
1177  }
1178 
1179  bm->totvertsel = bm->totedgesel = bm->totfacesel = 0;
1180  }
1181  else {
1182  for (i = 0; i < 3; i++) {
1183  BMIter iter;
1184  BMElem *ele;
1185 
1186  if (htype & flag_types[i]) {
1187  ele = BM_iter_new(&iter, bm, iter_types[i], NULL);
1188  for (; ele; ele = BM_iter_step(&iter)) {
1189 
1190  if (UNLIKELY(respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN))) {
1191  /* pass */
1192  }
1193  else if (!hflag_test || BM_elem_flag_test(ele, hflag_test)) {
1194  if (hflag & BM_ELEM_SELECT) {
1195  BM_elem_select_set(bm, ele, false);
1196  }
1197  BM_elem_flag_disable(ele, hflag);
1198  }
1199  else if (overwrite) {
1200  /* no match! */
1201  if (hflag & BM_ELEM_SELECT) {
1202  BM_elem_select_set(bm, ele, true);
1203  }
1204  BM_elem_flag_enable(ele, hflag_nosel);
1205  }
1206  }
1207  }
1208  }
1209  }
1210 }
1211 
1213  const char htype,
1214  const char hflag,
1215  const bool respecthide,
1216  const bool overwrite,
1217  const char hflag_test)
1218 {
1219  const char iter_types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
1220 
1221  const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
1222 
1223  /* use the nosel version when setting so under no
1224  * condition may a hidden face become selected.
1225  * Applying other flags to hidden faces is OK. */
1226  const char hflag_nosel = hflag & ~BM_ELEM_SELECT;
1227 
1228  BMIter iter;
1229  BMElem *ele;
1230  int i;
1231 
1232  BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
1233 
1234  /* note, better not attempt a fast path for selection as done with de-select
1235  * because hidden geometry and different selection modes can give different results,
1236  * we could of course check for no hidden faces and then use
1237  * quicker method but its not worth it. */
1238 
1239  for (i = 0; i < 3; i++) {
1240  if (htype & flag_types[i]) {
1241  ele = BM_iter_new(&iter, bm, iter_types[i], NULL);
1242  for (; ele; ele = BM_iter_step(&iter)) {
1243 
1244  if (UNLIKELY(respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN))) {
1245  /* pass */
1246  }
1247  else if (!hflag_test || BM_elem_flag_test(ele, hflag_test)) {
1248  /* match! */
1249  if (hflag & BM_ELEM_SELECT) {
1250  BM_elem_select_set(bm, ele, true);
1251  }
1252  BM_elem_flag_enable(ele, hflag_nosel);
1253  }
1254  else if (overwrite) {
1255  /* no match! */
1256  if (hflag & BM_ELEM_SELECT) {
1257  BM_elem_select_set(bm, ele, false);
1258  }
1259  BM_elem_flag_disable(ele, hflag);
1260  }
1261  }
1262  }
1263  }
1264 }
1265 
1267  const char htype,
1268  const char hflag,
1269  const bool respecthide)
1270 {
1271  /* call with 0 hflag_test */
1272  BM_mesh_elem_hflag_disable_test(bm, htype, hflag, respecthide, false, 0);
1273 }
1274 
1276  const char htype,
1277  const char hflag,
1278  const bool respecthide)
1279 {
1280  /* call with 0 hflag_test */
1281  BM_mesh_elem_hflag_enable_test(bm, htype, hflag, respecthide, false, 0);
1282 }
1283 
1284 /***************** Mesh Hiding stuff *********** */
1285 
1291 {
1293 }
1294 
1300 {
1302 }
1303 
1304 void BM_vert_hide_set(BMVert *v, const bool hide)
1305 {
1306  /* vert hiding: vert + surrounding edges and faces */
1307  BLI_assert(v->head.htype == BM_VERT);
1308  if (hide) {
1310  }
1311 
1313 
1314  if (v->e) {
1315  BMEdge *e_iter, *e_first;
1316  e_iter = e_first = v->e;
1317  do {
1318  BM_elem_flag_set(e_iter, BM_ELEM_HIDDEN, hide);
1319  if (e_iter->l) {
1320  const BMLoop *l_radial_iter, *l_radial_first;
1321  l_radial_iter = l_radial_first = e_iter->l;
1322  do {
1323  BM_elem_flag_set(l_radial_iter->f, BM_ELEM_HIDDEN, hide);
1324  } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
1325  }
1326  } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
1327  }
1328 }
1329 
1330 void BM_edge_hide_set(BMEdge *e, const bool hide)
1331 {
1332  BLI_assert(e->head.htype == BM_EDGE);
1333  if (hide) {
1335  }
1336 
1337  /* edge hiding: faces around the edge */
1338  if (e->l) {
1339  const BMLoop *l_iter, *l_first;
1340  l_iter = l_first = e->l;
1341  do {
1342  BM_elem_flag_set(l_iter->f, BM_ELEM_HIDDEN, hide);
1343  } while ((l_iter = l_iter->radial_next) != l_first);
1344  }
1345 
1347 
1348  /* hide vertices if necessary */
1349  if (hide) {
1350  vert_flush_hide_set(e->v1);
1351  vert_flush_hide_set(e->v2);
1352  }
1353  else {
1356  }
1357 }
1358 
1359 void BM_face_hide_set(BMFace *f, const bool hide)
1360 {
1361  BLI_assert(f->head.htype == BM_FACE);
1362  if (hide) {
1364  }
1365 
1366  BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide);
1367 
1368  if (hide) {
1369  BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
1370  BMLoop *l_iter;
1371 
1372  l_iter = l_first;
1373  do {
1374  edge_flush_hide_set(l_iter->e);
1375  } while ((l_iter = l_iter->next) != l_first);
1376 
1377  l_iter = l_first;
1378  do {
1379  vert_flush_hide_set(l_iter->v);
1380  } while ((l_iter = l_iter->next) != l_first);
1381  }
1382  else {
1383  BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
1384  BMLoop *l_iter;
1385 
1386  l_iter = l_first;
1387  do {
1390  } while ((l_iter = l_iter->next) != l_first);
1391  }
1392 }
1393 
1394 void _bm_elem_hide_set(BMesh *bm, BMHeader *head, const bool hide)
1395 {
1396  /* Follow convention of always deselecting before
1397  * hiding an element */
1398  switch (head->htype) {
1399  case BM_VERT:
1400  if (hide) {
1401  BM_vert_select_set(bm, (BMVert *)head, false);
1402  }
1403  BM_vert_hide_set((BMVert *)head, hide);
1404  break;
1405  case BM_EDGE:
1406  if (hide) {
1407  BM_edge_select_set(bm, (BMEdge *)head, false);
1408  }
1409  BM_edge_hide_set((BMEdge *)head, hide);
1410  break;
1411  case BM_FACE:
1412  if (hide) {
1413  BM_face_select_set(bm, (BMFace *)head, false);
1414  }
1415  BM_face_hide_set((BMFace *)head, hide);
1416  break;
1417  default:
1418  BMESH_ASSERT(0);
1419  break;
1420  }
1421 }
#define BLI_assert(a)
Definition: BLI_assert.h:58
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:756
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void * BLI_ghash_lookup(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:803
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:87
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:281
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:352
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:547
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void * BLI_findptr(const struct ListBase *listbase, const void *ptr, const 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:270
#define UNLIKELY(x)
#define SCE_SELECT_FACE
#define SCE_SELECT_VERTEX
#define SCE_SELECT_EDGE
Read Guarded memory(de)allocation.
#define BM_ALL_NOLOOP
Definition: bmesh_class.h:411
@ 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 BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:553
#define BMESH_ASSERT(a)
Definition: bmesh_error.h:76
#define BM_elem_flag_disable(ele, hflag)
Definition: bmesh_inline.h:29
#define BM_elem_flag_set(ele, hflag, val)
Definition: bmesh_inline.h:30
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
#define BM_elem_flag_test_bool(ele, hflag)
Definition: bmesh_inline.h:27
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:28
#define BM_ITER_MESH(ele, iter, bm, itype)
@ 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
void BM_select_history_clear(BMesh *bm)
BMEdge * BM_mesh_active_edge_get(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)
void _bm_select_history_store_head_notest(BMesh *bm, BMHeader *ele)
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)
bool _bm_select_history_remove(BMesh *bm, BMHeader *ele)
static void recount_totsels(BMesh *bm)
Definition: bmesh_marking.c:43
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 bool bm_vert_is_edge_select_any_other(const BMVert *v, const BMEdge *e_first)
Definition: bmesh_marking.c:73
void _bm_select_history_store_after(BMesh *bm, BMEditSelection *ese_ref, BMHeader *ele)
static BMEditSelection * bm_select_history_create(BMHeader *ele)
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)
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)
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 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)
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)
bool BM_select_history_active_get(BMesh *bm, BMEditSelection *ese)
void BM_face_hide_set(BMFace *f, const bool hide)
void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode)
Select Mode Flush.
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)
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)
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)
Definition: bmesh_private.h:76
#define BM_ELEM_API_FLAG_TEST(element, f)
Definition: bmesh_private.h:81
@ _FLAG_OVERLAP
Definition: bmesh_private.h:64
#define BM_ELEM_API_FLAG_ENABLE(element, f)
Definition: bmesh_private.h:71
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()
int count
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
BMVert * v1
Definition: bmesh_class.h:134
BMVert * v2
Definition: bmesh_class.h:134
struct BMLoop * l
Definition: bmesh_class.h:140
struct BMEditSelection * next
Definition: bmesh_marking.h:24
struct BMEditSelection * prev
Definition: bmesh_marking.h:24
BMHeader head
Definition: bmesh_class.h:255
BMHeader head
Definition: bmesh_class.h:267
float no[3]
Definition: bmesh_class.h:280
char htype
Definition: bmesh_class.h:76
struct BMVert * v
Definition: bmesh_class.h:165
struct BMEdge * e
Definition: bmesh_class.h:176
struct BMLoop * radial_next
Definition: bmesh_class.h:216
struct BMFace * f
Definition: bmesh_class.h:183
struct BMLoop * next
Definition: bmesh_class.h:245
float co[3]
Definition: bmesh_class.h:99
struct BMEdge * e
Definition: bmesh_class.h:109
float no[3]
Definition: bmesh_class.h:100
BMHeader head
Definition: bmesh_class.h:97
int totfacesel
Definition: bmesh_class.h:298
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
void * last
Definition: DNA_listBase.h:47
void * first
Definition: DNA_listBase.h:47
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: util_avxb.h:167