1c7aeb12a071f1c0fe4cfcd97c6eadd7c1bec118
[blender.git] / source / blender / bmesh / intern / bmesh_marking.c
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
17 /** \file
18  * \ingroup bmesh
19  *
20  * Selection routines for bmesh structures.
21  * This is actually all old code ripped from
22  * editmesh_lib.c and slightly modified to work
23  * for bmesh's. This also means that it has some
24  * of the same problems.... something that
25  * that should be addressed eventually.
26  */
27
28 #include <stddef.h>
29
30 #include "MEM_guardedalloc.h"
31
32 #include "DNA_scene_types.h"
33
34 #include "BLI_math.h"
35 #include "BLI_listbase.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 (tot * sel) variables */
50   bm->totvertsel = bm->totedgesel = bm->totfacesel = 0;
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]) {
61       if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
62         count += 1;
63       }
64     }
65     *tots[i] = count;
66   }
67 }
68
69 /** \name BMesh helper functions for selection & hide flushing.
70  * \{ */
71
72 static bool bm_vert_is_edge_select_any_other(const BMVert *v, const BMEdge *e_first)
73 {
74   const BMEdge *e_iter = e_first;
75
76   /* start by stepping over the current edge */
77   while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first) {
78     if (BM_elem_flag_test(e_iter, BM_ELEM_SELECT)) {
79       return true;
80     }
81   }
82   return false;
83 }
84
85 #if 0
86 static bool bm_vert_is_edge_select_any(const BMVert *v)
87 {
88   if (v->e) {
89     const BMEdge *e_iter, *e_first;
90     e_iter = e_first = v->e;
91     do {
92       if (BM_elem_flag_test(e_iter, BM_ELEM_SELECT)) {
93         return true;
94       }
95     } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
96   }
97   return false;
98 }
99 #endif
100
101 static bool bm_vert_is_edge_visible_any(const BMVert *v)
102 {
103   if (v->e) {
104     const BMEdge *e_iter, *e_first;
105     e_iter = e_first = v->e;
106     do {
107       if (!BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN)) {
108         return true;
109       }
110     } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
111   }
112   return false;
113 }
114
115 static bool bm_edge_is_face_select_any_other(BMLoop *l_first)
116 {
117   const BMLoop *l_iter = l_first;
118
119   /* start by stepping over the current face */
120   while ((l_iter = l_iter->radial_next) != l_first) {
121     if (BM_elem_flag_test(l_iter->f, BM_ELEM_SELECT)) {
122       return true;
123     }
124   }
125   return false;
126 }
127
128 #if 0
129 static bool bm_edge_is_face_select_any(const BMEdge *e)
130 {
131   if (e->l) {
132     const BMLoop *l_iter, *l_first;
133     l_iter = l_first = e->l;
134     do {
135       if (BM_elem_flag_test(l_iter->f, BM_ELEM_SELECT)) {
136         return true;
137       }
138     } while ((l_iter = l_iter->radial_next) != l_first);
139   }
140   return false;
141 }
142 #endif
143
144 static bool bm_edge_is_face_visible_any(const BMEdge *e)
145 {
146   if (e->l) {
147     const BMLoop *l_iter, *l_first;
148     l_iter = l_first = e->l;
149     do {
150       if (!BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
151         return true;
152       }
153     } while ((l_iter = l_iter->radial_next) != l_first);
154   }
155   return false;
156 }
157
158 /** \} */
159
160 /**
161  * \brief Select Mode Clean
162  *
163  * Remove isolated selected elements when in a mode doesn't support them.
164  * eg: in edge-mode a selected vertex must be connected to a selected edge.
165  *
166  * \note this could be made apart of #BM_mesh_select_mode_flush_ex
167  */
168 void BM_mesh_select_mode_clean_ex(BMesh *bm, const short selectmode)
169 {
170   if (selectmode & SCE_SELECT_VERTEX) {
171     /* pass */
172   }
173   else if (selectmode & SCE_SELECT_EDGE) {
174     BMIter iter;
175
176     if (bm->totvertsel) {
177       BMVert *v;
178       BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
179         BM_elem_flag_disable(v, BM_ELEM_SELECT);
180       }
181       bm->totvertsel = 0;
182     }
183
184     if (bm->totedgesel) {
185       BMEdge *e;
186       BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
187         if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
188           BM_vert_select_set(bm, e->v1, true);
189           BM_vert_select_set(bm, e->v2, true);
190         }
191       }
192     }
193   }
194   else if (selectmode & SCE_SELECT_FACE) {
195     BMIter iter;
196
197     if (bm->totvertsel) {
198       BMVert *v;
199       BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
200         BM_elem_flag_disable(v, BM_ELEM_SELECT);
201       }
202       bm->totvertsel = 0;
203     }
204
205     if (bm->totedgesel) {
206       BMEdge *e;
207       BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
208         BM_elem_flag_disable(e, BM_ELEM_SELECT);
209       }
210       bm->totedgesel = 0;
211     }
212
213     if (bm->totfacesel) {
214       BMFace *f;
215       BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
216         if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
217           BMLoop *l_iter, *l_first;
218           l_iter = l_first = BM_FACE_FIRST_LOOP(f);
219           do {
220             BM_edge_select_set(bm, l_iter->e, true);
221           } while ((l_iter = l_iter->next) != l_first);
222         }
223       }
224     }
225   }
226 }
227
228 void BM_mesh_select_mode_clean(BMesh *bm)
229 {
230   BM_mesh_select_mode_clean_ex(bm, bm->selectmode);
231 }
232
233 /**
234  * \brief Select Mode Flush
235  *
236  * Makes sure to flush selections 'upwards'
237  * (ie: all verts of an edge selects the edge and so on).
238  * This should only be called by system and not tool authors.
239  */
240 void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode)
241 {
242   BMEdge *e;
243   BMLoop *l_iter;
244   BMLoop *l_first;
245   BMFace *f;
246
247   BMIter eiter;
248   BMIter fiter;
249
250   if (selectmode & SCE_SELECT_VERTEX) {
251     /* both loops only set edge/face flags and read off verts */
252     BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
253       if (BM_elem_flag_test(e->v1, BM_ELEM_SELECT) && BM_elem_flag_test(e->v2, BM_ELEM_SELECT) &&
254           !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
255         BM_elem_flag_enable(e, BM_ELEM_SELECT);
256       }
257       else {
258         BM_elem_flag_disable(e, BM_ELEM_SELECT);
259       }
260     }
261     BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
262       bool ok = true;
263       if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
264         l_iter = l_first = BM_FACE_FIRST_LOOP(f);
265         do {
266           if (!BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
267             ok = false;
268             break;
269           }
270         } while ((l_iter = l_iter->next) != l_first);
271       }
272       else {
273         ok = false;
274       }
275
276       BM_elem_flag_set(f, BM_ELEM_SELECT, ok);
277     }
278   }
279   else if (selectmode & SCE_SELECT_EDGE) {
280     BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
281       bool ok = true;
282       if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
283         l_iter = l_first = BM_FACE_FIRST_LOOP(f);
284         do {
285           if (!BM_elem_flag_test(l_iter->e, BM_ELEM_SELECT)) {
286             ok = false;
287             break;
288           }
289         } while ((l_iter = l_iter->next) != l_first);
290       }
291       else {
292         ok = false;
293       }
294
295       BM_elem_flag_set(f, BM_ELEM_SELECT, ok);
296     }
297   }
298
299   /* Remove any deselected elements from the BMEditSelection */
300   BM_select_history_validate(bm);
301
302   recount_totsels(bm);
303 }
304
305 void BM_mesh_select_mode_flush(BMesh *bm)
306 {
307   BM_mesh_select_mode_flush_ex(bm, bm->selectmode);
308 }
309
310 /**
311  * mode independent flushing up/down
312  */
313 void BM_mesh_deselect_flush(BMesh *bm)
314 {
315   BMIter eiter;
316   BMEdge *e;
317
318   BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
319     if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
320       if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
321         if (!BM_elem_flag_test(e->v1, BM_ELEM_SELECT) ||
322             !BM_elem_flag_test(e->v2, BM_ELEM_SELECT)) {
323           BM_elem_flag_disable(e, BM_ELEM_SELECT);
324         }
325       }
326
327       if (e->l && !BM_elem_flag_test(e, BM_ELEM_SELECT)) {
328         BMLoop *l_iter;
329         BMLoop *l_first;
330
331         l_iter = l_first = e->l;
332         do {
333           BM_elem_flag_disable(l_iter->f, BM_ELEM_SELECT);
334         } while ((l_iter = l_iter->radial_next) != l_first);
335       }
336     }
337   }
338
339   /* Remove any deselected elements from the BMEditSelection */
340   BM_select_history_validate(bm);
341
342   recount_totsels(bm);
343 }
344
345 /**
346  * mode independent flushing up/down
347  */
348 void BM_mesh_select_flush(BMesh *bm)
349 {
350   BMEdge *e;
351   BMLoop *l_iter;
352   BMLoop *l_first;
353   BMFace *f;
354
355   BMIter eiter;
356   BMIter fiter;
357
358   bool ok;
359
360   BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
361     if (BM_elem_flag_test(e->v1, BM_ELEM_SELECT) && BM_elem_flag_test(e->v2, BM_ELEM_SELECT) &&
362         !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
363       BM_elem_flag_enable(e, BM_ELEM_SELECT);
364     }
365   }
366   BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
367     ok = true;
368     if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
369       l_iter = l_first = BM_FACE_FIRST_LOOP(f);
370       do {
371         if (!BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
372           ok = false;
373           break;
374         }
375       } while ((l_iter = l_iter->next) != l_first);
376     }
377     else {
378       ok = false;
379     }
380
381     if (ok) {
382       BM_elem_flag_enable(f, BM_ELEM_SELECT);
383     }
384   }
385
386   recount_totsels(bm);
387 }
388
389 /**
390  * \brief Select Vert
391  *
392  * Changes selection state of a single vertex
393  * in a mesh
394  */
395 void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
396 {
397   BLI_assert(v->head.htype == BM_VERT);
398
399   if (BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
400     return;
401   }
402
403   if (select) {
404     if (!BM_elem_flag_test(v, BM_ELEM_SELECT)) {
405       BM_elem_flag_enable(v, BM_ELEM_SELECT);
406       bm->totvertsel += 1;
407     }
408   }
409   else {
410     if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
411       bm->totvertsel -= 1;
412       BM_elem_flag_disable(v, BM_ELEM_SELECT);
413     }
414   }
415 }
416
417 /**
418  * \brief Select Edge
419  *
420  * Changes selection state of a single edge in a mesh.
421  */
422 void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
423 {
424   BLI_assert(e->head.htype == BM_EDGE);
425
426   if (BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
427     return;
428   }
429
430   if (select) {
431     if (!BM_elem_flag_test(e, BM_ELEM_SELECT)) {
432       BM_elem_flag_enable(e, BM_ELEM_SELECT);
433       bm->totedgesel += 1;
434     }
435     BM_vert_select_set(bm, e->v1, true);
436     BM_vert_select_set(bm, e->v2, true);
437   }
438   else {
439     if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
440       BM_elem_flag_disable(e, BM_ELEM_SELECT);
441       bm->totedgesel -= 1;
442     }
443
444     if ((bm->selectmode & SCE_SELECT_VERTEX) == 0) {
445       int i;
446
447       /* check if the vert is used by a selected edge */
448       for (i = 0; i < 2; i++) {
449         BMVert *v = *((&e->v1) + i);
450         if (bm_vert_is_edge_select_any_other(v, e) == false) {
451           BM_vert_select_set(bm, v, false);
452         }
453       }
454     }
455     else {
456       BM_vert_select_set(bm, e->v1, false);
457       BM_vert_select_set(bm, e->v2, false);
458     }
459   }
460 }
461
462 /**
463  * \brief Select Face
464  *
465  * Changes selection state of a single
466  * face in a mesh.
467  */
468 void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
469 {
470   BMLoop *l_iter;
471   BMLoop *l_first;
472
473   BLI_assert(f->head.htype == BM_FACE);
474
475   if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
476     return;
477   }
478
479   if (select) {
480     if (!BM_elem_flag_test(f, BM_ELEM_SELECT)) {
481       BM_elem_flag_enable(f, BM_ELEM_SELECT);
482       bm->totfacesel += 1;
483     }
484
485     l_iter = l_first = BM_FACE_FIRST_LOOP(f);
486     do {
487       BM_vert_select_set(bm, l_iter->v, true);
488       BM_edge_select_set(bm, l_iter->e, true);
489     } while ((l_iter = l_iter->next) != l_first);
490   }
491   else {
492
493     if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
494       BM_elem_flag_disable(f, BM_ELEM_SELECT);
495       bm->totfacesel -= 1;
496     }
497     /**
498      * \note This allows a temporarily invalid state - where for eg
499      * an edge bay be de-selected, but an adjacent face remains selected.
500      *
501      * Rely on #BM_mesh_select_mode_flush to correct these cases.
502      *
503      * \note flushing based on mode, see T46494
504      */
505     if (bm->selectmode & SCE_SELECT_VERTEX) {
506       l_iter = l_first = BM_FACE_FIRST_LOOP(f);
507       do {
508         BM_vert_select_set(bm, l_iter->v, false);
509         BM_edge_select_set_noflush(bm, l_iter->e, false);
510       } while ((l_iter = l_iter->next) != l_first);
511     }
512     else {
513       /**
514        * \note use #BM_edge_select_set_noflush,
515        * vertex flushing is handled last.
516        */
517       if (bm->selectmode & SCE_SELECT_EDGE) {
518         l_iter = l_first = BM_FACE_FIRST_LOOP(f);
519         do {
520           BM_edge_select_set_noflush(bm, l_iter->e, false);
521         } while ((l_iter = l_iter->next) != l_first);
522       }
523       else {
524         l_iter = l_first = BM_FACE_FIRST_LOOP(f);
525         do {
526           if (bm_edge_is_face_select_any_other(l_iter) == false) {
527             BM_edge_select_set_noflush(bm, l_iter->e, false);
528           }
529         } while ((l_iter = l_iter->next) != l_first);
530       }
531
532       /* flush down to verts */
533       l_iter = l_first = BM_FACE_FIRST_LOOP(f);
534       do {
535         if (bm_vert_is_edge_select_any_other(l_iter->v, l_iter->e) == false) {
536           BM_vert_select_set(bm, l_iter->v, false);
537         }
538       } while ((l_iter = l_iter->next) != l_first);
539     }
540   }
541 }
542
543 /** \name Non flushing versions element selection.
544  * \{ */
545
546 void BM_edge_select_set_noflush(BMesh *bm, BMEdge *e, const bool select)
547 {
548   BLI_assert(e->head.htype == BM_EDGE);
549
550   if (BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
551     return;
552   }
553
554   if (select) {
555     if (!BM_elem_flag_test(e, BM_ELEM_SELECT)) {
556       BM_elem_flag_enable(e, BM_ELEM_SELECT);
557       bm->totedgesel += 1;
558     }
559   }
560   else {
561     if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
562       BM_elem_flag_disable(e, BM_ELEM_SELECT);
563       bm->totedgesel -= 1;
564     }
565   }
566 }
567
568 void BM_face_select_set_noflush(BMesh *bm, BMFace *f, const bool select)
569 {
570   BLI_assert(f->head.htype == BM_FACE);
571
572   if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
573     return;
574   }
575
576   if (select) {
577     if (!BM_elem_flag_test(f, BM_ELEM_SELECT)) {
578       BM_elem_flag_enable(f, BM_ELEM_SELECT);
579       bm->totfacesel += 1;
580     }
581   }
582   else {
583     if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
584       BM_elem_flag_disable(f, BM_ELEM_SELECT);
585       bm->totfacesel -= 1;
586     }
587   }
588 }
589
590 /** \} */
591
592 /**
593  * Select Mode Set
594  *
595  * Sets the selection mode for the bmesh,
596  * updating the selection state.
597  */
598 void BM_mesh_select_mode_set(BMesh *bm, int selectmode)
599 {
600   BMIter iter;
601   BMElem *ele;
602
603   bm->selectmode = selectmode;
604
605   if (bm->selectmode & SCE_SELECT_VERTEX) {
606     /* disabled because selection flushing handles these */
607 #if 0
608     BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
609       BM_elem_flag_disable(ele, BM_ELEM_SELECT);
610     }
611     BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
612       BM_elem_flag_disable(ele, BM_ELEM_SELECT);
613     }
614 #endif
615     BM_mesh_select_mode_flush(bm);
616   }
617   else if (bm->selectmode & SCE_SELECT_EDGE) {
618     /* disabled because selection flushing handles these */
619 #if 0
620     BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
621       BM_elem_flag_disable(ele, BM_ELEM_SELECT);
622     }
623 #endif
624
625     BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
626       if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
627         BM_edge_select_set(bm, (BMEdge *)ele, true);
628       }
629     }
630     BM_mesh_select_mode_flush(bm);
631   }
632   else if (bm->selectmode & SCE_SELECT_FACE) {
633     /* disabled because selection flushing handles these */
634 #if 0
635     BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
636       BM_elem_flag_disable(ele, BM_ELEM_SELECT);
637     }
638 #endif
639     BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
640       if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
641         BM_face_select_set(bm, (BMFace *)ele, true);
642       }
643     }
644     BM_mesh_select_mode_flush(bm);
645   }
646 }
647
648 /**
649  * counts number of elements with flag enabled/disabled
650  */
651 static int bm_mesh_flag_count(BMesh *bm,
652                               const char htype,
653                               const char hflag,
654                               const bool respecthide,
655                               const bool test_for_enabled)
656 {
657   BMElem *ele;
658   BMIter iter;
659   int tot = 0;
660
661   BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
662
663   if (htype & BM_VERT) {
664     BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
665       if (respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) {
666         continue;
667       }
668       if (BM_elem_flag_test_bool(ele, hflag) == test_for_enabled) {
669         tot++;
670       }
671     }
672   }
673   if (htype & BM_EDGE) {
674     BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
675       if (respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) {
676         continue;
677       }
678       if (BM_elem_flag_test_bool(ele, hflag) == test_for_enabled) {
679         tot++;
680       }
681     }
682   }
683   if (htype & BM_FACE) {
684     BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
685       if (respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) {
686         continue;
687       }
688       if (BM_elem_flag_test_bool(ele, hflag) == test_for_enabled) {
689         tot++;
690       }
691     }
692   }
693
694   return tot;
695 }
696
697 int BM_mesh_elem_hflag_count_enabled(BMesh *bm,
698                                      const char htype,
699                                      const char hflag,
700                                      const bool respecthide)
701 {
702   return bm_mesh_flag_count(bm, htype, hflag, respecthide, true);
703 }
704
705 int BM_mesh_elem_hflag_count_disabled(BMesh *bm,
706                                       const char htype,
707                                       const char hflag,
708                                       const bool respecthide)
709 {
710   return bm_mesh_flag_count(bm, htype, hflag, respecthide, false);
711 }
712
713 /**
714  * \note use BM_elem_flag_test(ele, BM_ELEM_SELECT) to test selection
715  * \note by design, this will not touch the editselection history stuff
716  */
717 void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select)
718 {
719   switch (ele->head.htype) {
720     case BM_VERT:
721       BM_vert_select_set(bm, (BMVert *)ele, select);
722       break;
723     case BM_EDGE:
724       BM_edge_select_set(bm, (BMEdge *)ele, select);
725       break;
726     case BM_FACE:
727       BM_face_select_set(bm, (BMFace *)ele, select);
728       break;
729     default:
730       BLI_assert(0);
731       break;
732   }
733 }
734
735 /* this replaces the active flag used in uv/face mode */
736 void BM_mesh_active_face_set(BMesh *bm, BMFace *efa)
737 {
738   bm->act_face = efa;
739 }
740
741 BMFace *BM_mesh_active_face_get(BMesh *bm, const bool is_sloppy, const bool is_selected)
742 {
743   if (bm->act_face && (!is_selected || BM_elem_flag_test(bm->act_face, BM_ELEM_SELECT))) {
744     return bm->act_face;
745   }
746   else if (is_sloppy) {
747     BMIter iter;
748     BMFace *f = NULL;
749     BMEditSelection *ese;
750
751     /* Find the latest non-hidden face from the BMEditSelection */
752     ese = bm->selected.last;
753     for (; ese; ese = ese->prev) {
754       if (ese->htype == BM_FACE) {
755         f = (BMFace *)ese->ele;
756
757         if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
758           f = NULL;
759         }
760         else if (is_selected && !BM_elem_flag_test(f, BM_ELEM_SELECT)) {
761           f = NULL;
762         }
763         else {
764           break;
765         }
766       }
767     }
768     /* Last attempt: try to find any selected face */
769     if (f == NULL) {
770       BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
771         if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
772           break;
773         }
774       }
775     }
776     return f; /* can still be null */
777   }
778   return NULL;
779 }
780
781 BMEdge *BM_mesh_active_edge_get(BMesh *bm)
782 {
783   if (bm->selected.last) {
784     BMEditSelection *ese = bm->selected.last;
785
786     if (ese && ese->htype == BM_EDGE) {
787       return (BMEdge *)ese->ele;
788     }
789   }
790
791   return NULL;
792 }
793
794 BMVert *BM_mesh_active_vert_get(BMesh *bm)
795 {
796   if (bm->selected.last) {
797     BMEditSelection *ese = bm->selected.last;
798
799     if (ese && ese->htype == BM_VERT) {
800       return (BMVert *)ese->ele;
801     }
802   }
803
804   return NULL;
805 }
806
807 BMElem *BM_mesh_active_elem_get(BMesh *bm)
808 {
809   if (bm->selected.last) {
810     BMEditSelection *ese = bm->selected.last;
811
812     if (ese) {
813       return ese->ele;
814     }
815   }
816
817   return NULL;
818 }
819
820 /**
821  * Generic way to get data from an EditSelection type
822  * These functions were written to be used by the Modifier widget
823  * when in Rotate about active mode, but can be used anywhere.
824  *
825  * - #BM_editselection_center
826  * - #BM_editselection_normal
827  * - #BM_editselection_plane
828  */
829 void BM_editselection_center(BMEditSelection *ese, float r_center[3])
830 {
831   if (ese->htype == BM_VERT) {
832     BMVert *eve = (BMVert *)ese->ele;
833     copy_v3_v3(r_center, eve->co);
834   }
835   else if (ese->htype == BM_EDGE) {
836     BMEdge *eed = (BMEdge *)ese->ele;
837     mid_v3_v3v3(r_center, eed->v1->co, eed->v2->co);
838   }
839   else if (ese->htype == BM_FACE) {
840     BMFace *efa = (BMFace *)ese->ele;
841     BM_face_calc_center_median(efa, r_center);
842   }
843 }
844
845 void BM_editselection_normal(BMEditSelection *ese, float r_normal[3])
846 {
847   if (ese->htype == BM_VERT) {
848     BMVert *eve = (BMVert *)ese->ele;
849     copy_v3_v3(r_normal, eve->no);
850   }
851   else if (ese->htype == BM_EDGE) {
852     BMEdge *eed = (BMEdge *)ese->ele;
853     float plane[3]; /* need a plane to correct the normal */
854     float vec[3];   /* temp vec storage */
855
856     add_v3_v3v3(r_normal, eed->v1->no, eed->v2->no);
857     sub_v3_v3v3(plane, eed->v2->co, eed->v1->co);
858
859     /* the 2 vertex normals will be close but not at right angles to the edge
860      * for rotate about edge we want them to be at right angles, so we need to
861      * do some extra calculation to correct the vert normals,
862      * we need the plane for this */
863     cross_v3_v3v3(vec, r_normal, plane);
864     cross_v3_v3v3(r_normal, plane, vec);
865     normalize_v3(r_normal);
866   }
867   else if (ese->htype == BM_FACE) {
868     BMFace *efa = (BMFace *)ese->ele;
869     copy_v3_v3(r_normal, efa->no);
870   }
871 }
872
873 /* Calculate a plane that is rightangles to the edge/vert/faces normal
874  * also make the plane run along an axis that is related to the geometry,
875  * because this is used for the gizmos Y axis. */
876 void BM_editselection_plane(BMEditSelection *ese, float r_plane[3])
877 {
878   if (ese->htype == BM_VERT) {
879     BMVert *eve = (BMVert *)ese->ele;
880     float vec[3] = {0.0f, 0.0f, 0.0f};
881
882     if (ese->prev) { /* use previously selected data to make a useful vertex plane */
883       BM_editselection_center(ese->prev, vec);
884       sub_v3_v3v3(r_plane, vec, eve->co);
885     }
886     else {
887       /* make a fake plane thats at rightangles to the normal
888        * we can't make a crossvec from a vec that's the same as the vec
889        * unlikely but possible, so make sure if the normal is (0, 0, 1)
890        * that vec isn't the same or in the same direction even. */
891       if (eve->no[0] < 0.5f) {
892         vec[0] = 1.0f;
893       }
894       else if (eve->no[1] < 0.5f) {
895         vec[1] = 1.0f;
896       }
897       else {
898         vec[2] = 1.0f;
899       }
900       cross_v3_v3v3(r_plane, eve->no, vec);
901     }
902     normalize_v3(r_plane);
903   }
904   else if (ese->htype == BM_EDGE) {
905     BMEdge *eed = (BMEdge *)ese->ele;
906
907     if (BM_edge_is_boundary(eed)) {
908       sub_v3_v3v3(r_plane, eed->l->v->co, eed->l->next->v->co);
909     }
910     else {
911       /* the plane is simple, it runs along the edge
912        * however selecting different edges can swap the direction of the y axis.
913        * this makes it less likely for the y axis of the gizmo
914        * (running along the edge).. to flip less often.
915        * at least its more predictable */
916       if (eed->v2->co[1] > eed->v1->co[1]) { /* check which to do first */
917         sub_v3_v3v3(r_plane, eed->v2->co, eed->v1->co);
918       }
919       else {
920         sub_v3_v3v3(r_plane, eed->v1->co, eed->v2->co);
921       }
922     }
923
924     normalize_v3(r_plane);
925   }
926   else if (ese->htype == BM_FACE) {
927     BMFace *efa = (BMFace *)ese->ele;
928     BM_face_calc_tangent_auto(efa, r_plane);
929   }
930 }
931
932 static BMEditSelection *bm_select_history_create(BMHeader *ele)
933 {
934   BMEditSelection *ese = (BMEditSelection *)MEM_callocN(sizeof(BMEditSelection),
935                                                         "BMEdit Selection");
936   ese->htype = ele->htype;
937   ese->ele = (BMElem *)ele;
938   return ese;
939 }
940
941 /* --- macro wrapped funcs --- */
942 bool _bm_select_history_check(BMesh *bm, const BMHeader *ele)
943 {
944   return (BLI_findptr(&bm->selected, ele, offsetof(BMEditSelection, ele)) != NULL);
945 }
946
947 bool _bm_select_history_remove(BMesh *bm, BMHeader *ele)
948 {
949   BMEditSelection *ese = BLI_findptr(&bm->selected, ele, offsetof(BMEditSelection, ele));
950   if (ese) {
951     BLI_freelinkN(&bm->selected, ese);
952     return true;
953   }
954   else {
955     return false;
956   }
957 }
958
959 void _bm_select_history_store_notest(BMesh *bm, BMHeader *ele)
960 {
961   BMEditSelection *ese = bm_select_history_create(ele);
962   BLI_addtail(&(bm->selected), ese);
963 }
964
965 void _bm_select_history_store_head_notest(BMesh *bm, BMHeader *ele)
966 {
967   BMEditSelection *ese = bm_select_history_create(ele);
968   BLI_addhead(&(bm->selected), ese);
969 }
970
971 void _bm_select_history_store(BMesh *bm, BMHeader *ele)
972 {
973   if (!BM_select_history_check(bm, (BMElem *)ele)) {
974     BM_select_history_store_notest(bm, (BMElem *)ele);
975   }
976 }
977
978 void _bm_select_history_store_head(BMesh *bm, BMHeader *ele)
979 {
980   if (!BM_select_history_check(bm, (BMElem *)ele)) {
981     BM_select_history_store_head_notest(bm, (BMElem *)ele);
982   }
983 }
984
985 void _bm_select_history_store_after_notest(BMesh *bm, BMEditSelection *ese_ref, BMHeader *ele)
986 {
987   BMEditSelection *ese = bm_select_history_create(ele);
988   BLI_insertlinkafter(&(bm->selected), ese_ref, ese);
989 }
990
991 void _bm_select_history_store_after(BMesh *bm, BMEditSelection *ese_ref, BMHeader *ele)
992 {
993   if (!BM_select_history_check(bm, (BMElem *)ele)) {
994     BM_select_history_store_after_notest(bm, ese_ref, (BMElem *)ele);
995   }
996 }
997 /* --- end macro wrapped funcs --- */
998
999 void BM_select_history_clear(BMesh *bm)
1000 {
1001   BLI_freelistN(&bm->selected);
1002 }
1003
1004 void BM_select_history_validate(BMesh *bm)
1005 {
1006   BMEditSelection *ese, *ese_next;
1007
1008   for (ese = bm->selected.first; ese; ese = ese_next) {
1009     ese_next = ese->next;
1010     if (!BM_elem_flag_test(ese->ele, BM_ELEM_SELECT)) {
1011       BLI_freelinkN(&(bm->selected), ese);
1012     }
1013   }
1014 }
1015
1016 /**
1017  * Get the active mesh element (with active-face fallback).
1018  */
1019 bool BM_select_history_active_get(BMesh *bm, BMEditSelection *ese)
1020 {
1021   BMEditSelection *ese_last = bm->selected.last;
1022   BMFace *efa = BM_mesh_active_face_get(bm, false, false);
1023
1024   ese->next = ese->prev = NULL;
1025
1026   if (ese_last) {
1027     if (ese_last->htype ==
1028         BM_FACE) { /* if there is an active face, use it over the last selected face */
1029       if (efa) {
1030         ese->ele = (BMElem *)efa;
1031       }
1032       else {
1033         ese->ele = ese_last->ele;
1034       }
1035       ese->htype = BM_FACE;
1036     }
1037     else {
1038       ese->ele = ese_last->ele;
1039       ese->htype = ese_last->htype;
1040     }
1041   }
1042   else if (efa) {
1043     /* no edit-selection, fallback to active face */
1044     ese->ele = (BMElem *)efa;
1045     ese->htype = BM_FACE;
1046   }
1047   else {
1048     ese->ele = NULL;
1049     return false;
1050   }
1051
1052   return true;
1053 }
1054
1055 /**
1056  * Return a map from BMVert/Edge/Face -> BMEditSelection
1057  */
1058 GHash *BM_select_history_map_create(BMesh *bm)
1059 {
1060   BMEditSelection *ese;
1061   GHash *map;
1062
1063   if (BLI_listbase_is_empty(&bm->selected)) {
1064     return NULL;
1065   }
1066
1067   map = BLI_ghash_ptr_new(__func__);
1068
1069   for (ese = bm->selected.first; ese; ese = ese->next) {
1070     BLI_ghash_insert(map, ese->ele, ese);
1071   }
1072
1073   return map;
1074 }
1075
1076 /**
1077  * Map arguments may all be the same pointer.
1078  */
1079 void BM_select_history_merge_from_targetmap(
1080     BMesh *bm, GHash *vert_map, GHash *edge_map, GHash *face_map, const bool use_chain)
1081 {
1082
1083 #ifdef DEBUG
1084   for (BMEditSelection *ese = bm->selected.first; ese; ese = ese->next) {
1085     BLI_assert(BM_ELEM_API_FLAG_TEST(ese->ele, _FLAG_OVERLAP) == 0);
1086   }
1087 #endif
1088
1089   for (BMEditSelection *ese = bm->selected.first; ese; ese = ese->next) {
1090     BM_ELEM_API_FLAG_ENABLE(ese->ele, _FLAG_OVERLAP);
1091
1092     /* Only loop when (use_chain == true). */
1093     GHash *map = NULL;
1094     switch (ese->ele->head.htype) {
1095       case BM_VERT:
1096         map = vert_map;
1097         break;
1098       case BM_EDGE:
1099         map = edge_map;
1100         break;
1101       case BM_FACE:
1102         map = face_map;
1103         break;
1104       default:
1105         BMESH_ASSERT(0);
1106         break;
1107     }
1108     if (map != NULL) {
1109       BMElem *ele_dst = ese->ele;
1110       while (true) {
1111         BMElem *ele_dst_next = BLI_ghash_lookup(map, ele_dst);
1112         BLI_assert(ele_dst != ele_dst_next);
1113         if (ele_dst_next == NULL) {
1114           break;
1115         }
1116         ele_dst = ele_dst_next;
1117         /* Break loop on circular reference (should never happen). */
1118         if (UNLIKELY(ele_dst == ese->ele)) {
1119           BLI_assert(0);
1120           break;
1121         }
1122         if (use_chain == false) {
1123           break;
1124         }
1125       }
1126       ese->ele = ele_dst;
1127     }
1128   }
1129
1130   /* Remove overlapping duplicates. */
1131   for (BMEditSelection *ese = bm->selected.first, *ese_next; ese; ese = ese_next) {
1132     ese_next = ese->next;
1133     if (BM_ELEM_API_FLAG_TEST(ese->ele, _FLAG_OVERLAP)) {
1134       BM_ELEM_API_FLAG_DISABLE(ese->ele, _FLAG_OVERLAP);
1135     }
1136     else {
1137       BLI_freelinkN(&bm->selected, ese);
1138     }
1139   }
1140 }
1141
1142 void BM_mesh_elem_hflag_disable_test(BMesh *bm,
1143                                      const char htype,
1144                                      const char hflag,
1145                                      const bool respecthide,
1146                                      const bool overwrite,
1147                                      const char hflag_test)
1148 {
1149   const char iter_types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
1150
1151   const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
1152
1153   const char hflag_nosel = hflag & ~BM_ELEM_SELECT;
1154
1155   int i;
1156
1157   BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
1158
1159   if (hflag & BM_ELEM_SELECT) {
1160     BM_select_history_clear(bm);
1161   }
1162
1163   if ((htype == (BM_VERT | BM_EDGE | BM_FACE)) && (hflag == BM_ELEM_SELECT) &&
1164       (respecthide == false) && (hflag_test == 0)) {
1165     /* fast path for deselect all, avoid topology loops
1166      * since we know all will be de-selected anyway. */
1167     for (i = 0; i < 3; i++) {
1168       BMIter iter;
1169       BMElem *ele;
1170
1171       ele = BM_iter_new(&iter, bm, iter_types[i], NULL);
1172       for (; ele; ele = BM_iter_step(&iter)) {
1173         BM_elem_flag_disable(ele, BM_ELEM_SELECT);
1174       }
1175     }
1176
1177     bm->totvertsel = bm->totedgesel = bm->totfacesel = 0;
1178   }
1179   else {
1180     for (i = 0; i < 3; i++) {
1181       BMIter iter;
1182       BMElem *ele;
1183
1184       if (htype & flag_types[i]) {
1185         ele = BM_iter_new(&iter, bm, iter_types[i], NULL);
1186         for (; ele; ele = BM_iter_step(&iter)) {
1187
1188           if (UNLIKELY(respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN))) {
1189             /* pass */
1190           }
1191           else if (!hflag_test || BM_elem_flag_test(ele, hflag_test)) {
1192             if (hflag & BM_ELEM_SELECT) {
1193               BM_elem_select_set(bm, ele, false);
1194             }
1195             BM_elem_flag_disable(ele, hflag);
1196           }
1197           else if (overwrite) {
1198             /* no match! */
1199             if (hflag & BM_ELEM_SELECT) {
1200               BM_elem_select_set(bm, ele, true);
1201             }
1202             BM_elem_flag_enable(ele, hflag_nosel);
1203           }
1204         }
1205       }
1206     }
1207   }
1208 }
1209
1210 void BM_mesh_elem_hflag_enable_test(BMesh *bm,
1211                                     const char htype,
1212                                     const char hflag,
1213                                     const bool respecthide,
1214                                     const bool overwrite,
1215                                     const char hflag_test)
1216 {
1217   const char iter_types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
1218
1219   const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
1220
1221   /* use the nosel version when setting so under no
1222    * condition may a hidden face become selected.
1223    * Applying other flags to hidden faces is OK. */
1224   const char hflag_nosel = hflag & ~BM_ELEM_SELECT;
1225
1226   BMIter iter;
1227   BMElem *ele;
1228   int i;
1229
1230   BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
1231
1232   /* note, better not attempt a fast path for selection as done with de-select
1233    * because hidden geometry and different selection modes can give different results,
1234    * we could of course check for no hidden faces and then use
1235    * quicker method but its not worth it. */
1236
1237   for (i = 0; i < 3; i++) {
1238     if (htype & flag_types[i]) {
1239       ele = BM_iter_new(&iter, bm, iter_types[i], NULL);
1240       for (; ele; ele = BM_iter_step(&iter)) {
1241
1242         if (UNLIKELY(respecthide && BM_elem_flag_test(ele, BM_ELEM_HIDDEN))) {
1243           /* pass */
1244         }
1245         else if (!hflag_test || BM_elem_flag_test(ele, hflag_test)) {
1246           /* match! */
1247           if (hflag & BM_ELEM_SELECT) {
1248             BM_elem_select_set(bm, ele, true);
1249           }
1250           BM_elem_flag_enable(ele, hflag_nosel);
1251         }
1252         else if (overwrite) {
1253           /* no match! */
1254           if (hflag & BM_ELEM_SELECT) {
1255             BM_elem_select_set(bm, ele, false);
1256           }
1257           BM_elem_flag_disable(ele, hflag);
1258         }
1259       }
1260     }
1261   }
1262 }
1263
1264 void BM_mesh_elem_hflag_disable_all(BMesh *bm,
1265                                     const char htype,
1266                                     const char hflag,
1267                                     const bool respecthide)
1268 {
1269   /* call with 0 hflag_test */
1270   BM_mesh_elem_hflag_disable_test(bm, htype, hflag, respecthide, false, 0);
1271 }
1272
1273 void BM_mesh_elem_hflag_enable_all(BMesh *bm,
1274                                    const char htype,
1275                                    const char hflag,
1276                                    const bool respecthide)
1277 {
1278   /* call with 0 hflag_test */
1279   BM_mesh_elem_hflag_enable_test(bm, htype, hflag, respecthide, false, 0);
1280 }
1281
1282 /***************** Mesh Hiding stuff *********** */
1283
1284 /**
1285  * Hide unless any connected elements are visible.
1286  * Run this after hiding a connected edge or face.
1287  */
1288 static void vert_flush_hide_set(BMVert *v)
1289 {
1290   BM_elem_flag_set(v, BM_ELEM_HIDDEN, !bm_vert_is_edge_visible_any(v));
1291 }
1292
1293 /**
1294  * Hide unless any connected elements are visible.
1295  * Run this after hiding a connected face.
1296  */
1297 static void edge_flush_hide_set(BMEdge *e)
1298 {
1299   BM_elem_flag_set(e, BM_ELEM_HIDDEN, !bm_edge_is_face_visible_any(e));
1300 }
1301
1302 void BM_vert_hide_set(BMVert *v, const bool hide)
1303 {
1304   /* vert hiding: vert + surrounding edges and faces */
1305   BLI_assert(v->head.htype == BM_VERT);
1306   if (hide) {
1307     BLI_assert(!BM_elem_flag_test(v, BM_ELEM_SELECT));
1308   }
1309
1310   BM_elem_flag_set(v, BM_ELEM_HIDDEN, hide);
1311
1312   if (v->e) {
1313     BMEdge *e_iter, *e_first;
1314     e_iter = e_first = v->e;
1315     do {
1316       BM_elem_flag_set(e_iter, BM_ELEM_HIDDEN, hide);
1317       if (e_iter->l) {
1318         const BMLoop *l_radial_iter, *l_radial_first;
1319         l_radial_iter = l_radial_first = e_iter->l;
1320         do {
1321           BM_elem_flag_set(l_radial_iter->f, BM_ELEM_HIDDEN, hide);
1322         } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
1323       }
1324     } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
1325   }
1326 }
1327
1328 void BM_edge_hide_set(BMEdge *e, const bool hide)
1329 {
1330   BLI_assert(e->head.htype == BM_EDGE);
1331   if (hide) {
1332     BLI_assert(!BM_elem_flag_test(e, BM_ELEM_SELECT));
1333   }
1334
1335   /* edge hiding: faces around the edge */
1336   if (e->l) {
1337     const BMLoop *l_iter, *l_first;
1338     l_iter = l_first = e->l;
1339     do {
1340       BM_elem_flag_set(l_iter->f, BM_ELEM_HIDDEN, hide);
1341     } while ((l_iter = l_iter->radial_next) != l_first);
1342   }
1343
1344   BM_elem_flag_set(e, BM_ELEM_HIDDEN, hide);
1345
1346   /* hide vertices if necessary */
1347   if (hide) {
1348     vert_flush_hide_set(e->v1);
1349     vert_flush_hide_set(e->v2);
1350   }
1351   else {
1352     BM_elem_flag_disable(e->v1, BM_ELEM_HIDDEN);
1353     BM_elem_flag_disable(e->v2, BM_ELEM_HIDDEN);
1354   }
1355 }
1356
1357 void BM_face_hide_set(BMFace *f, const bool hide)
1358 {
1359   BLI_assert(f->head.htype == BM_FACE);
1360   if (hide) {
1361     BLI_assert(!BM_elem_flag_test(f, BM_ELEM_SELECT));
1362   }
1363
1364   BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide);
1365
1366   if (hide) {
1367     BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
1368     BMLoop *l_iter;
1369
1370     l_iter = l_first;
1371     do {
1372       edge_flush_hide_set(l_iter->e);
1373     } while ((l_iter = l_iter->next) != l_first);
1374
1375     l_iter = l_first;
1376     do {
1377       vert_flush_hide_set(l_iter->v);
1378     } while ((l_iter = l_iter->next) != l_first);
1379   }
1380   else {
1381     BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
1382     BMLoop *l_iter;
1383
1384     l_iter = l_first;
1385     do {
1386       BM_elem_flag_disable(l_iter->e, BM_ELEM_HIDDEN);
1387       BM_elem_flag_disable(l_iter->v, BM_ELEM_HIDDEN);
1388     } while ((l_iter = l_iter->next) != l_first);
1389   }
1390 }
1391
1392 void _bm_elem_hide_set(BMesh *bm, BMHeader *head, const bool hide)
1393 {
1394   /* Follow convention of always deselecting before
1395    * hiding an element */
1396   switch (head->htype) {
1397     case BM_VERT:
1398       if (hide) {
1399         BM_vert_select_set(bm, (BMVert *)head, false);
1400       }
1401       BM_vert_hide_set((BMVert *)head, hide);
1402       break;
1403     case BM_EDGE:
1404       if (hide) {
1405         BM_edge_select_set(bm, (BMEdge *)head, false);
1406       }
1407       BM_edge_hide_set((BMEdge *)head, hide);
1408       break;
1409     case BM_FACE:
1410       if (hide) {
1411         BM_face_select_set(bm, (BMFace *)head, false);
1412       }
1413       BM_face_hide_set((BMFace *)head, hide);
1414       break;
1415     default:
1416       BMESH_ASSERT(0);
1417       break;
1418   }
1419 }