part 1 of cleaning up my little array macro library to be a formal API. also removed...
[blender.git] / source / blender / bmesh / intern / bmesh_marking.c
1 #include "MEM_guardedalloc.h"
2
3 #include "BKE_utildefines.h"
4
5 #include "BLI_arithb.h"
6 #include "BLI_blenlib.h"
7 #include "BLI_array.h"
8
9 #include "bmesh.h"
10 #include "bmesh_private.h"
11
12 #include <string.h>
13
14 /*
15  * BM_MARK.C
16  *
17  * Selection routines for bmesh structures.
18  * This is actually all old code ripped from
19  * editmesh_lib.c and slightly modified to work
20  * for bmesh's. This also means that it has some
21  * of the same problems.... something that
22  * that should be addressed eventually.
23  *
24 */
25
26
27 /*
28  * BMESH SELECTMODE FLUSH
29  *
30  * Makes sure to flush selections 
31  * 'upwards' (ie: all verts of an edge
32  * selects the edge and so on). This 
33  * should only be called by system and not
34  * tool authors.
35  *
36 */
37
38 static void recount_totsels(BMesh *bm)
39 {
40         BMIter iter;
41         BMHeader *ele;
42         int types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
43         int *tots[3];
44         int i;
45
46         /*recount tot*sel variables*/
47         bm->totvertsel = bm->totedgesel = bm->totfacesel = 0;
48         tots[0] = &bm->totvertsel;
49         tots[1] = &bm->totedgesel;
50         tots[2] = &bm->totfacesel;
51
52         for (i=0; i<3; i++) {
53                 ele = BMIter_New(&iter, bm, types[i], NULL);
54                 for ( ; ele; ele=BMIter_Step(&iter)) {
55                         if (BM_TestHFlag(ele, BM_SELECT)) *tots[i] += 1;
56                 }
57         }
58 }
59
60 void BM_SelectMode_Flush(BMesh *bm)
61 {
62         BMEdge *e;
63         BMLoop *l;
64         BMFace *f;
65
66         BMIter edges;
67         BMIter faces;
68
69         int totsel;
70
71         if(bm->selectmode & SCE_SELECT_VERTEX) {
72                 for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm ); e; e= BMIter_Step(&edges)) {
73                         if(BM_TestHFlag(e->v1, BM_SELECT) && BM_TestHFlag(e->v2, BM_SELECT)) BM_SetHFlag(e, BM_SELECT);
74                         else BM_ClearHFlag(e, BM_SELECT);
75                 }
76                 for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f= BMIter_Step(&faces)) {
77                         totsel = 0;
78                         l=f->loopbase;
79                         do{
80                                 if(BM_TestHFlag(l->v, BM_SELECT)) 
81                                         totsel++;
82                                 l = ((BMLoop*)(l->head.next));
83                         } while(l != f->loopbase);
84                         
85                         if(totsel == f->len) 
86                                 BM_SetHFlag(f, BM_SELECT);
87                         else
88                                 BM_ClearHFlag(f, BM_SELECT);
89                 }
90         }
91         else if(bm->selectmode & SCE_SELECT_EDGE) {
92                 for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f= BMIter_Step(&faces)) {
93                         totsel = 0;
94                         l=f->loopbase;
95                         do{
96                                 if(bmesh_test_sysflag(&(l->e->head), BM_SELECT)) 
97                                         totsel++;
98                                 l = ((BMLoop*)(l->head.next));
99                         }while(l!=f->loopbase);
100                         
101                         if(totsel == f->len) 
102                                 BM_SetHFlag(f, BM_SELECT);
103                         else 
104                                 BM_ClearHFlag(f, BM_SELECT);
105                 }
106         }
107
108         recount_totsels(bm);
109 }
110
111 /*
112  * BMESH SELECT VERT
113  *
114  * Changes selection state of a single vertex 
115  * in a mesh
116  *
117 */
118
119 void BM_Select_Vert(BMesh *bm, BMVert *v, int select)
120 {
121         if(select) {
122                 if (!BM_TestHFlag(v, BM_SELECT)) bm->totvertsel += 1;
123                 BM_SetHFlag(v, BM_SELECT);
124         } else {
125                 if (BM_TestHFlag(v, BM_SELECT)) bm->totvertsel -= 1;
126                 BM_ClearHFlag(v, BM_SELECT);
127         }
128 }
129
130 /*
131  * BMESH SELECT EDGE
132  *
133  * Changes selection state of a single edge
134  * in a mesh. Note that this is actually not
135  * 100 percent reliable. Deselecting an edge
136  * will also deselect both its vertices
137  * regardless of the selection state of
138  * other edges incident upon it. Fixing this
139  * issue breaks multi-select mode though...
140  *
141 */
142
143 void BM_Select_Edge(BMesh *bm, BMEdge *e, int select)
144 {
145         int candesel;
146         int testiso = 1;
147
148         /*I might move this logic to bmeshutils_mods.c, where it'd be invoked
149           by the selection tools.  in that case, we'd still retain the checks
150           for if an edge's verts can be deselected.*/
151
152         /*ensure vert selections are valid, only if not in a multiselect
153           mode that shares SCE_SELECT_VERT*/
154         switch (bm->selectmode) {
155                 case SCE_SELECT_VERTEX:
156                 case SCE_SELECT_EDGE:
157                 case SCE_SELECT_FACE:
158                 case SCE_SELECT_EDGE|SCE_SELECT_FACE:
159                         testiso = 1;
160                         break;
161                 default:
162                         testiso = 0;
163                         break;
164         }
165
166         if (testiso && !select) {
167                 BMIter eiter;
168                 BMEdge *e2;
169                 int i;
170
171                 for (i=0; i<2; i++) {
172                         candesel = 1;
173                         e2 = BMIter_New(&eiter, bm, BM_EDGES_OF_VERT, !i?e->v1:e->v2);
174                         for (; e2; e2=BMIter_Step(&eiter)) {
175                                 if (e2 == e) continue;
176                                 if (BM_TestHFlag(e2, BM_SELECT)) {
177                                         candesel = 0;
178                                         break;
179                                 }
180                         }
181
182                         if (candesel) BM_Select_Vert(bm, !i?e->v1:e->v2, 0);                    
183                 }
184         }
185
186         if(select) { 
187                 if (!BM_TestHFlag(e, BM_SELECT)) bm->totedgesel += 1;
188
189                 BM_SetHFlag(&(e->head), BM_SELECT);
190                 BM_Select(bm, e->v1, 1);
191                 BM_Select(bm, e->v2, 1);
192         }
193         else{ 
194                 if (BM_TestHFlag(e, BM_SELECT)) bm->totedgesel -= 1;
195
196                 BM_ClearHFlag(&(e->head), BM_SELECT);
197         }
198 }
199
200 /*
201  *
202  * BMESH SELECT FACE
203  *
204  * Changes selection state of a single
205  * face in a mesh. This (might) suffer
206  * from same problems as edge select
207  * code...
208  *
209 */
210
211 void BM_Select_Face(BMesh *bm, BMFace *f, int select)
212 {
213         BMLoop *l;
214
215         if(select){ 
216                 if (!BM_TestHFlag(f, BM_SELECT)) bm->totfacesel += 1;
217
218                 BM_SetHFlag(&(f->head), BM_SELECT);
219                 l = f->loopbase;
220                 do{
221                         BM_Select_Vert(bm, l->v, 1);
222                         BM_Select_Edge(bm, l->e, 1);
223                         l = ((BMLoop*)(l->head.next));
224                 }while(l != f->loopbase);
225         }
226         else{ 
227                 BMIter liter, fiter, eiter;
228                 BMFace *f2;
229                 BMLoop *l;
230                 BMEdge *e;
231
232                 if (BM_TestHFlag(f, BM_SELECT)) bm->totfacesel -= 1;
233                 BM_ClearHFlag(&(f->head), BM_SELECT);
234
235                 /*flush down to edges*/
236                 BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
237                         BM_ITER(f2, &fiter, bm, BM_FACES_OF_EDGE, l->e) {
238                                 if (BM_TestHFlag(f2, BM_SELECT))
239                                         break;
240                         }
241
242                         if (!f2) {
243                                 BM_Select(bm, l->e, 0);
244                         }
245                 }
246
247                 /*flush down to verts*/
248                 BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
249                         BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, l->v) {
250                                 if (BM_TestHFlag(e, BM_SELECT))
251                                         break;
252                         }
253
254                         if (!e) {
255                                 BM_Select(bm, l->v, 0);
256                         }
257                 }
258         }
259 }
260
261 /*
262  * BMESH SELECTMODE SET
263  *
264  * Sets the selection mode for the bmesh
265  *
266 */
267
268 void BM_Selectmode_Set(BMesh *bm, int selectmode)
269 {
270         BMVert *v;
271         BMEdge *e;
272         BMFace *f;
273         
274         BMIter verts;
275         BMIter edges;
276         BMIter faces;
277         
278         bm->selectmode = selectmode;
279
280         if(bm->selectmode & SCE_SELECT_VERTEX) {
281                 for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm ); e; e= BMIter_Step(&edges))
282                         BM_ClearHFlag(e, 0);
283                 for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f= BMIter_Step(&faces))
284                         BM_ClearHFlag(f, 0);
285                 BM_SelectMode_Flush(bm);
286         }
287         else if(bm->selectmode & SCE_SELECT_EDGE) {
288                 for(v= BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm ); v; v= BMIter_Step(&verts))
289                         BM_ClearHFlag(v, 0);
290                 for(e= BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm ); e; e= BMIter_Step(&edges)){
291                         if(BM_TestHFlag(&(e->head), BM_SELECT))
292                                 BM_Select_Edge(bm, e, 1);
293                 }
294                 BM_SelectMode_Flush(bm);
295         }
296         else if(bm->selectmode & SCE_SELECT_FACE) {
297                 for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm ); e; e= BMIter_Step(&edges))
298                         BM_ClearHFlag(e, 0);
299                 for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f= BMIter_Step(&faces)){
300                         if(BM_TestHFlag(&(f->head), BM_SELECT))
301                                 BM_Select_Face(bm, f, 1);
302                 }
303                 BM_SelectMode_Flush(bm);
304         }
305 }
306
307
308 int BM_CountFlag(struct BMesh *bm, int type, int flag, int respecthide)
309 {
310         BMHeader *head;
311         BMIter iter;
312         int tot = 0;
313
314         if (type & BM_VERT) {
315                 for (head = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); head; head=BMIter_Step(&iter)) {
316                         if (respecthide && BM_TestHFlag(head, BM_HIDDEN)) continue;
317                         if (head->flag & flag) tot++;
318                 }
319         }
320         if (type & BM_EDGE) {
321                 for (head = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL); head; head=BMIter_Step(&iter)) {
322                         if (respecthide && BM_TestHFlag(head, BM_HIDDEN)) continue;
323                         if (head->flag & flag) tot++;
324                 }
325         }
326         if (type & BM_FACE) {
327                 for (head = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL); head; head=BMIter_Step(&iter)) {
328                         if (respecthide && BM_TestHFlag(head, BM_HIDDEN)) continue;
329                         if (head->flag & flag) tot++;
330                 }
331         }
332
333         return tot;
334 }
335
336 /*note: by design, this will not touch the editselection history stuff*/
337 void BM_Select(struct BMesh *bm, void *element, int select)
338 {
339         BMHeader *head = element;
340
341         if(head->type == BM_VERT) BM_Select_Vert(bm, (BMVert*)element, select);
342         else if(head->type == BM_EDGE) BM_Select_Edge(bm, (BMEdge*)element, select);
343         else if(head->type == BM_FACE) BM_Select_Face(bm, (BMFace*)element, select);
344 }
345
346 int BM_Selected(BMesh *bm, void *element)
347 {
348         BMHeader *head = element;
349         return BM_TestHFlag(head, BM_SELECT);
350 }
351
352
353 /* generic way to get data from an EditSelection type 
354 These functions were written to be used by the Modifier widget when in Rotate about active mode,
355 but can be used anywhere.
356 EM_editselection_center
357 EM_editselection_normal
358 EM_editselection_plane
359 */
360 void BM_editselection_center(BMesh *em, float *center, BMEditSelection *ese)
361 {
362         if (ese->type==BM_VERT) {
363                 BMVert *eve= ese->data;
364                 VecCopyf(center, eve->co);
365         } else if (ese->type==BM_EDGE) {
366                 BMEdge *eed= ese->data;
367                 VecAddf(center, eed->v1->co, eed->v2->co);
368                 VecMulf(center, 0.5);
369         } else if (ese->type==BM_FACE) {
370                 BMFace *efa= ese->data;
371                 BM_Compute_Face_Center(em, efa, center);
372         }
373 }
374
375 void BM_editselection_normal(float *normal, BMEditSelection *ese)
376 {
377         if (ese->type==BM_VERT) {
378                 BMVert *eve= ese->data;
379                 VecCopyf(normal, eve->no);
380         } else if (ese->type==BM_EDGE) {
381                 BMEdge *eed= ese->data;
382                 float plane[3]; /* need a plane to correct the normal */
383                 float vec[3]; /* temp vec storage */
384                 
385                 VecAddf(normal, eed->v1->no, eed->v2->no);
386                 VecSubf(plane, eed->v2->co, eed->v1->co);
387                 
388                 /* the 2 vertex normals will be close but not at rightangles to the edge
389                 for rotate about edge we want them to be at right angles, so we need to
390                 do some extra colculation to correct the vert normals,
391                 we need the plane for this */
392                 Crossf(vec, normal, plane);
393                 Crossf(normal, plane, vec); 
394                 Normalize(normal);
395                 
396         } else if (ese->type==BM_FACE) {
397                 BMFace *efa= ese->data;
398                 VecCopyf(normal, efa->no);
399         }
400 }
401
402 /* Calculate a plane that is rightangles to the edge/vert/faces normal
403 also make the plane run allong an axis that is related to the geometry,
404 because this is used for the manipulators Y axis.*/
405 void BM_editselection_plane(BMesh *em, float *plane, BMEditSelection *ese)
406 {
407         if (ese->type==BM_VERT) {
408                 BMVert *eve= ese->data;
409                 float vec[3]={0,0,0};
410                 
411                 if (ese->prev) { /*use previously selected data to make a usefull vertex plane */
412                         BM_editselection_center(em, vec, ese->prev);
413                         VecSubf(plane, vec, eve->co);
414                 } else {
415                         /* make a fake  plane thats at rightangles to the normal
416                         we cant make a crossvec from a vec thats the same as the vec
417                         unlikely but possible, so make sure if the normal is (0,0,1)
418                         that vec isnt the same or in the same direction even.*/
419                         if (eve->no[0]<0.5)             vec[0]=1;
420                         else if (eve->no[1]<0.5)        vec[1]=1;
421                         else                            vec[2]=1;
422                         Crossf(plane, eve->no, vec);
423                 }
424         } else if (ese->type==BM_EDGE) {
425                 BMEdge *eed= ese->data;
426
427                 /*the plane is simple, it runs allong the edge
428                 however selecting different edges can swap the direction of the y axis.
429                 this makes it less likely for the y axis of the manipulator
430                 (running along the edge).. to flip less often.
431                 at least its more pradictable */
432                 if (eed->v2->co[1] > eed->v1->co[1]) /*check which to do first */
433                         VecSubf(plane, eed->v2->co, eed->v1->co);
434                 else
435                         VecSubf(plane, eed->v1->co, eed->v2->co);
436                 
437         } else if (ese->type==BM_FACE) {
438                 BMFace *efa= ese->data;
439                 float vec[3] = {0.0f, 0.0f, 0.0f};
440                 
441                 /*for now, use face normal*/
442
443                 /* make a fake plane thats at rightangles to the normal
444                 we cant make a crossvec from a vec thats the same as the vec
445                 unlikely but possible, so make sure if the normal is (0,0,1)
446                 that vec isnt the same or in the same direction even.*/
447                 if (efa->no[0]<0.5)             vec[0]=1.0f;
448                 else if (efa->no[1]<0.5)        vec[1]=1.0f;
449                 else                            vec[2]=1.0f;
450                 Crossf(plane, efa->no, vec);
451 #if 0 //BMESH_TODO
452
453                 if (efa->v4) { /*if its a quad- set the plane along the 2 longest edges.*/
454                         float vecA[3], vecB[3];
455                         VecSubf(vecA, efa->v4->co, efa->v3->co);
456                         VecSubf(vecB, efa->v1->co, efa->v2->co);
457                         VecAddf(plane, vecA, vecB);
458                         
459                         VecSubf(vecA, efa->v1->co, efa->v4->co);
460                         VecSubf(vecB, efa->v2->co, efa->v3->co);
461                         VecAddf(vec, vecA, vecB);                                               
462                         /*use the biggest edge length*/
463                         if (plane[0]*plane[0]+plane[1]*plane[1]+plane[2]*plane[2] < vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2])
464                                 VecCopyf(plane, vec);
465                 } else {
466                         /*start with v1-2 */
467                         VecSubf(plane, efa->v1->co, efa->v2->co);
468                         
469                         /*test the edge between v2-3, use if longer */
470                         VecSubf(vec, efa->v2->co, efa->v3->co);
471                         if (plane[0]*plane[0]+plane[1]*plane[1]+plane[2]*plane[2] < vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2])
472                                 VecCopyf(plane, vec);
473                         
474                         /*test the edge between v1-3, use if longer */
475                         VecSubf(vec, efa->v3->co, efa->v1->co);
476                         if (plane[0]*plane[0]+plane[1]*plane[1]+plane[2]*plane[2] < vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2])
477                                 VecCopyf(plane, vec);
478                 }
479 #endif
480         }
481         Normalize(plane);
482 }
483
484 static int BM_check_selection(BMesh *em, void *data)
485 {
486         BMEditSelection *ese;
487         
488         for(ese = em->selected.first; ese; ese = ese->next){
489                 if(ese->data == data) return 1;
490         }
491         
492         return 0;
493 }
494
495 void BM_remove_selection(BMesh *em, void *data)
496 {
497         BMEditSelection *ese;
498         for(ese=em->selected.first; ese; ese = ese->next){
499                 if(ese->data == data){
500                         BLI_freelinkN(&(em->selected),ese);
501                         break;
502                 }
503         }
504 }
505
506 void BM_clear_selection_history(BMesh *em)
507 {
508         BLI_freelistN(&em->selected);
509         em->selected.first = em->selected.last = NULL;
510 }
511
512 void BM_store_selection(BMesh *em, void *data)
513 {
514         BMEditSelection *ese;
515         if(!BM_check_selection(em, data)){
516                 ese = (BMEditSelection*) MEM_callocN( sizeof(BMEditSelection), "BMEdit Selection");
517                 ese->type = ((BMHeader*)data)->type;
518                 ese->data = data;
519                 BLI_addtail(&(em->selected),ese);
520         }
521 }
522
523 void BM_validate_selections(BMesh *em)
524 {
525         BMEditSelection *ese, *nextese;
526
527         ese = em->selected.first;
528
529         while(ese){
530                 nextese = ese->next;
531                 if (!BM_TestHFlag(ese->data, BM_SELECT)) BLI_freelinkN(&(em->selected), ese);
532                 ese = nextese;
533         }
534 }
535
536 void BM_clear_flag_all(BMesh *bm, int flag)
537 {
538         BMIter iter;
539         BMHeader *ele;
540         int i, type;
541
542         if (flag & BM_SELECT)
543                 BM_clear_selection_history(bm);
544
545         for (i=0; i<3; i++) {
546                 switch (i) {
547                         case 0:
548                                 type = BM_VERTS_OF_MESH;
549                                 break;
550                         case 1:
551                                 type = BM_EDGES_OF_MESH;
552                                 break;
553                         case 2:
554                                 type = BM_FACES_OF_MESH;
555                                 break;
556                 }
557                 
558                 ele = BMIter_New(&iter, bm, type, NULL);
559                 for ( ; ele; ele=BMIter_Step(&iter)) {
560                         if (flag & BM_SELECT) BM_Select(bm, ele, 0);
561                         BM_ClearHFlag(ele, flag);
562                 }
563         }
564 }
565
566
567 /***************** Pinning **************/
568
569 #define SETPIN(ele) pin ? BM_SetHFlag(ele, BM_PINNED) : BM_ClearHFlag(ele, BM_PINNED);
570
571
572 void BM_Pin_Vert(BMesh *bm, BMVert *v, int pin)
573 {
574         SETPIN(v);
575 }
576
577 void BM_Pin_Edge(BMesh *bm, BMEdge *e, int pin)
578 {
579         SETPIN(e->v1);
580         SETPIN(e->v2);
581 }
582
583 void BM_Pin_Face(BMesh *bm, BMFace *f, int pin)
584 {
585         BMIter vfiter;
586         BMVert *vf;
587
588         BM_ITER(vf, &vfiter, bm, BM_VERTS_OF_FACE, f) {
589                 SETPIN(vf);
590         }
591 }
592
593 void BM_Pin(BMesh *bm, void *element, int pin)
594 {
595         BMHeader *h = element;
596
597         switch (h->type) {
598                 case BM_VERT:
599                         BM_Pin_Vert(bm, element, pin);
600                         break;
601                 case BM_EDGE:
602                         BM_Pin_Edge(bm, element, pin);
603                         break;
604                 case BM_FACE:
605                         BM_Pin_Face(bm, element, pin);
606                         break;
607         }
608 }
609
610
611
612 /***************** Mesh Hiding stuff *************/
613
614 #define SETHIDE(ele) hide ? BM_SetHFlag(ele, BM_HIDDEN) : BM_ClearHFlag(ele, BM_HIDDEN);
615
616 static void vert_flush_hide(BMesh *bm, BMVert *v) {
617         BMIter iter;
618         BMEdge *e;
619
620         BM_ITER(e, &iter, bm, BM_EDGES_OF_VERT, v) {
621                 if (!BM_TestHFlag(e, BM_HIDDEN))
622                         return;
623         }
624
625         BM_SetHFlag(v, BM_HIDDEN);
626 }
627
628 static void edge_flush_hide(BMesh *bm, BMEdge *e) {
629         BMIter iter;
630         BMFace *f;
631
632         BM_ITER(f, &iter, bm, BM_FACES_OF_EDGE, e) {
633                 if (!BM_TestHFlag(f, BM_HIDDEN))
634                         return;
635         }
636
637         BM_SetHFlag(e, BM_HIDDEN);
638 }
639
640 void BM_Hide_Vert(BMesh *bm, BMVert *v, int hide)
641 {
642         /*vert hiding: vert + surrounding edges and faces*/
643         BMIter iter, fiter;
644         BMEdge *e;
645         BMFace *f;
646
647         SETHIDE(v);
648
649         BM_ITER(e, &iter, bm, BM_EDGES_OF_VERT, v) {
650                 SETHIDE(e);
651
652                 BM_ITER(f, &fiter, bm, BM_FACES_OF_EDGE, e) {
653                         SETHIDE(f);
654                 }
655         }
656 }
657
658 void BM_Hide_Edge(BMesh *bm, BMEdge *e, int hide)
659 {
660         BMIter iter;
661         BMFace *f;
662         BMVert *v;
663
664         /*edge hiding: faces around the edge*/
665         BM_ITER(f, &iter, bm, BM_FACES_OF_EDGE, e) {
666                 SETHIDE(f);
667         }
668         
669         SETHIDE(e);
670
671         /*hide vertices if necassary*/
672         vert_flush_hide(bm, e->v1);
673         vert_flush_hide(bm, e->v2);
674 }
675
676 void BM_Hide_Face(BMesh *bm, BMFace *f, int hide)
677 {
678         BMIter iter;
679         BMLoop *l;
680
681         /**/
682         SETHIDE(f);
683
684         BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) {
685                 edge_flush_hide(bm, l->e);
686         }
687
688         BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) {
689                 vert_flush_hide(bm, l->v);
690         }
691 }
692
693 void BM_Hide(BMesh *bm, void *element, int hide)
694 {
695         BMHeader *h = element;
696
697         switch (h->type) {
698                 case BM_VERT:
699                         BM_Hide_Vert(bm, element, hide);
700                         break;
701                 case BM_EDGE:
702                         BM_Hide_Edge(bm, element, hide);
703                         break;
704                 case BM_FACE:
705                         BM_Hide_Face(bm, element, hide);
706                         break;
707         }
708 }
709
710