Code Cleanup:
[blender-staging.git] / source / blender / bmesh / intern / bmesh_marking.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Joseph Eagar, Geoffrey Bantle, Campbell Barton
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/bmesh/intern/bmesh_marking.c
24  *  \ingroup bmesh
25  *
26  * Selection routines for bmesh structures.
27  * This is actually all old code ripped from
28  * editmesh_lib.c and slightly modified to work
29  * for bmesh's. This also means that it has some
30  * of the same problems.... something that
31  * that should be addressed eventually.
32  */
33
34 #include "MEM_guardedalloc.h"
35
36 #include "BKE_utildefines.h"
37
38 #include "BLI_math.h"
39 #include "BLI_listbase.h"
40
41 #include "bmesh.h"
42 #include "bmesh_private.h"
43
44 #include <string.h>
45
46 /*
47  * BMESH SELECTMODE FLUSH
48  *
49  * Makes sure to flush selections
50  * 'upwards' (ie: all verts of an edge
51  * selects the edge and so on). This
52  * should only be called by system and not
53  * tool authors.
54  *
55  */
56
57 static void recount_totsels(BMesh *bm)
58 {
59         BMIter iter;
60         BMHeader *ele;
61         const char iter_types[3] = {BM_VERTS_OF_MESH,
62                                     BM_EDGES_OF_MESH,
63                                     BM_FACES_OF_MESH};
64         int *tots[3];
65         int i;
66
67         /* recount (tot * sel) variables */
68         bm->totvertsel = bm->totedgesel = bm->totfacesel = 0;
69         tots[0] = &bm->totvertsel;
70         tots[1] = &bm->totedgesel;
71         tots[2] = &bm->totfacesel;
72
73         for (i = 0; i < 3; i++) {
74                 ele = BMIter_New(&iter, bm, iter_types[i], NULL);
75                 for ( ; ele; ele = BMIter_Step(&iter)) {
76                         if (BM_TestHFlag(ele, BM_SELECT)) *tots[i] += 1;
77                 }
78         }
79 }
80
81 void BM_SelectMode_Flush(BMesh *bm)
82 {
83         BMEdge *e;
84         BMLoop *l_iter;
85         BMLoop *l_first;
86         BMFace *f;
87
88         BMIter edges;
89         BMIter faces;
90
91         int totsel;
92
93         if (bm->selectmode & SCE_SELECT_VERTEX) {
94                 for (e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)) {
95                         if (BM_TestHFlag(e->v1, BM_SELECT) && BM_TestHFlag(e->v2, BM_SELECT) && !BM_TestHFlag(e, BM_HIDDEN)) {
96                                 BM_SetHFlag(e, BM_SELECT);
97                         }
98                         else {
99                                 BM_ClearHFlag(e, BM_SELECT);
100                         }
101                 }
102                 for (f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)) {
103                         totsel = 0;
104                         l_iter = l_first = BM_FACE_FIRST_LOOP(f);
105                         do {
106                                 if (BM_TestHFlag(l_iter->v, BM_SELECT)) {
107                                         totsel++;
108                                 }
109                         } while ((l_iter = l_iter->next) != l_first);
110                         
111                         if (totsel == f->len && !BM_TestHFlag(f, BM_HIDDEN)) {
112                                 BM_SetHFlag(f, BM_SELECT);
113                         }
114                         else {
115                                 BM_ClearHFlag(f, BM_SELECT);
116                         }
117                 }
118         }
119         else if (bm->selectmode & SCE_SELECT_EDGE) {
120                 for (f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)) {
121                         totsel = 0;
122                         l_iter = l_first = BM_FACE_FIRST_LOOP(f);
123                         do {
124                                 if (BM_TestHFlag(&(l_iter->e->head), BM_SELECT)) {
125                                         totsel++;
126                                 }
127                         } while ((l_iter = l_iter->next) != l_first);
128                         
129                         if (totsel == f->len && !BM_TestHFlag(f, BM_HIDDEN)) {
130                                 BM_SetHFlag(f, BM_SELECT);
131                         }
132                         else {
133                                 BM_ClearHFlag(f, BM_SELECT);
134                         }
135                 }
136         }
137
138         /* Remove any deselected elements from the BMEditSelection */
139         BM_validate_selections(bm);
140
141         recount_totsels(bm);
142 }
143
144 /*
145  * BMESH SELECT VERT
146  *
147  * Changes selection state of a single vertex
148  * in a mesh
149  *
150  */
151
152 void BM_Select_Vert(BMesh *bm, BMVert *v, int select)
153 {
154         /* BMIter iter; */
155         /* BMEdge *e; */
156
157         if (BM_TestHFlag(v, BM_HIDDEN)) {
158                 return;
159         }
160
161         if (select) {
162                 if (!BM_TestHFlag(v, BM_SELECT)) {
163                         bm->totvertsel += 1;
164                         BM_SetHFlag(v, BM_SELECT);
165                 }
166         }
167         else {
168                 if (BM_TestHFlag(v, BM_SELECT)) {
169                         bm->totvertsel -= 1;
170                         BM_ClearHFlag(v, BM_SELECT);
171                 }
172         }
173 }
174
175 /*
176  * BMESH SELECT EDGE
177  *
178  * Changes selection state of a single edge
179  * in a mesh.
180  *
181  */
182
183 void BM_Select_Edge(BMesh *bm, BMEdge *e, int select)
184 {
185         if (BM_TestHFlag(e, BM_HIDDEN)) {
186                 return;
187         }
188
189         if (select) {
190                 if (!BM_TestHFlag(e, BM_SELECT)) bm->totedgesel += 1;
191
192                 BM_SetHFlag(&(e->head), BM_SELECT);
193                 BM_Select(bm, e->v1, TRUE);
194                 BM_Select(bm, e->v2, TRUE);
195         }
196         else {
197                 if (BM_TestHFlag(e, BM_SELECT)) bm->totedgesel -= 1;
198                 BM_ClearHFlag(&(e->head), BM_SELECT);
199
200                 if ( bm->selectmode == SCE_SELECT_EDGE ||
201                      bm->selectmode == SCE_SELECT_FACE ||
202                      bm->selectmode == (SCE_SELECT_EDGE | SCE_SELECT_FACE))
203                 {
204
205                         BMIter iter;
206                         BMVert *verts[2] = {e->v1, e->v2};
207                         BMEdge *e2;
208                         int i;
209
210                         for (i = 0; i < 2; i++) {
211                                 int deselect = 1;
212
213                                 for (e2 = BMIter_New(&iter, bm, BM_EDGES_OF_VERT, verts[i]); e2; e2 = BMIter_Step(&iter)) {
214                                         if (e2 == e) {
215                                                 continue;
216                                         }
217
218                                         if (BM_TestHFlag(e2, BM_SELECT)) {
219                                                 deselect = 0;
220                                                 break;
221                                         }
222                                 }
223
224                                 if (deselect) BM_Select_Vert(bm, verts[i], FALSE);
225                         }
226                 }
227                 else {
228                         BM_Select(bm, e->v1, FALSE);
229                         BM_Select(bm, e->v2, FALSE);
230                 }
231
232         }
233 }
234
235 /*
236  *
237  * BMESH SELECT FACE
238  *
239  * Changes selection state of a single
240  * face in a mesh.
241  *
242  */
243
244 void BM_Select_Face(BMesh *bm, BMFace *f, int select)
245 {
246         BMLoop *l_iter;
247         BMLoop *l_first;
248
249         if (BM_TestHFlag(f, BM_HIDDEN)) {
250                 return;
251         }
252
253         if (select) {
254                 if (!BM_TestHFlag(f, BM_SELECT)) bm->totfacesel += 1;
255
256                 BM_SetHFlag(&(f->head), BM_SELECT);
257                 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
258                 do {
259                         BM_Select_Vert(bm, l_iter->v, TRUE);
260                         BM_Select_Edge(bm, l_iter->e, TRUE);
261                 } while ((l_iter = l_iter->next) != l_first);
262         }
263         else {
264                 BMIter liter;
265                 BMLoop *l;
266
267                 if (BM_TestHFlag(f, BM_SELECT)) bm->totfacesel -= 1;
268                 BM_ClearHFlag(&(f->head), BM_SELECT);
269
270                 /* flush down to edges */
271                 BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
272                         BMIter fiter;
273                         BMFace *f2;
274                         BM_ITER(f2, &fiter, bm, BM_FACES_OF_EDGE, l->e) {
275                                 if (BM_TestHFlag(f2, BM_SELECT))
276                                         break;
277                         }
278
279                         if (!f2)
280                         {
281                                 BM_Select(bm, l->e, FALSE);
282                         }
283                 }
284
285                 /* flush down to verts */
286                 BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
287                         BMIter eiter;
288                         BMEdge *e;
289                         BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, l->v) {
290                                 if (BM_TestHFlag(e, BM_SELECT))
291                                         break;
292                         }
293
294                         if (!e) {
295                                 BM_Select(bm, l->v, FALSE);
296                         }
297                 }
298         }
299 }
300
301 /*
302  * BMESH SELECTMODE SET
303  *
304  * Sets the selection mode for the bmesh
305  *
306  */
307
308 void BM_Selectmode_Set(BMesh *bm, int selectmode)
309 {
310         BMVert *v;
311         BMEdge *e;
312         BMFace *f;
313         
314         BMIter verts;
315         BMIter edges;
316         BMIter faces;
317         
318         bm->selectmode = selectmode;
319
320         if (bm->selectmode & SCE_SELECT_VERTEX) {
321                 for (e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges))
322                         BM_ClearHFlag(e, 0);
323                 for (f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces))
324                         BM_ClearHFlag(f, 0);
325                 BM_SelectMode_Flush(bm);
326         }
327         else if (bm->selectmode & SCE_SELECT_EDGE) {
328                 for (v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts))
329                         BM_ClearHFlag(v, 0);
330                 for (e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)) {
331                         if (BM_TestHFlag(&(e->head), BM_SELECT)) {
332                                 BM_Select_Edge(bm, e, TRUE);
333                         }
334                 }
335                 BM_SelectMode_Flush(bm);
336         }
337         else if (bm->selectmode & SCE_SELECT_FACE) {
338                 for (e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges))
339                         BM_ClearHFlag(e, 0);
340                 for (f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)) {
341                         if (BM_TestHFlag(&(f->head), BM_SELECT)) {
342                                 BM_Select_Face(bm, f, TRUE);
343                         }
344                 }
345                 BM_SelectMode_Flush(bm);
346         }
347 }
348
349
350 int BM_CountFlag(struct BMesh *bm, const char htype, const char hflag, int respecthide)
351 {
352         BMHeader *head;
353         BMIter iter;
354         int tot = 0;
355
356         if (htype & BM_VERT) {
357                 for (head = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); head; head = BMIter_Step(&iter)) {
358                         if (respecthide && BM_TestHFlag(head, BM_HIDDEN)) continue;
359                         if (BM_TestHFlag(head, hflag)) tot++;
360                 }
361         }
362         if (htype & BM_EDGE) {
363                 for (head = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL); head; head = BMIter_Step(&iter)) {
364                         if (respecthide && BM_TestHFlag(head, BM_HIDDEN)) continue;
365                         if (BM_TestHFlag(head, hflag)) tot++;
366                 }
367         }
368         if (htype & BM_FACE) {
369                 for (head = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL); head; head = BMIter_Step(&iter)) {
370                         if (respecthide && BM_TestHFlag(head, BM_HIDDEN)) continue;
371                         if (BM_TestHFlag(head, hflag)) tot++;
372                 }
373         }
374
375         return tot;
376 }
377
378 /* note: by design, this will not touch the editselection history stuff */
379 void BM_Select(struct BMesh *bm, void *element, int select)
380 {
381         BMHeader *head = element;
382
383         if      (head->htype == BM_VERT) BM_Select_Vert(bm, (BMVert *)element, select);
384         else if (head->htype == BM_EDGE) BM_Select_Edge(bm, (BMEdge *)element, select);
385         else if (head->htype == BM_FACE) BM_Select_Face(bm, (BMFace *)element, select);
386 }
387
388 int BM_Selected(BMesh *UNUSED(bm), const void *element)
389 {
390         const BMHeader *head = element;
391         int selected = BM_TestHFlag(head, BM_SELECT);
392         BLI_assert(!selected || !BM_TestHFlag(head, BM_HIDDEN));
393         return selected;
394 }
395
396 /* this replaces the active flag used in uv/face mode */
397 void BM_set_actFace(BMesh *bm, BMFace *efa)
398 {
399         bm->act_face = efa;
400 }
401
402 BMFace *BM_get_actFace(BMesh *bm, int sloppy)
403 {
404         if (bm->act_face) {
405                 return bm->act_face;
406         }
407         else if (sloppy) {
408                 BMIter iter;
409                 BMFace *f = NULL;
410                 BMEditSelection *ese;
411                 
412                 /* Find the latest non-hidden face from the BMEditSelection */
413                 ese = bm->selected.last;
414                 for ( ; ese; ese = ese->prev) {
415                         if (ese->htype == BM_FACE) {
416                                 f = (BMFace *)ese->data;
417                                 
418                                 if (BM_TestHFlag(f, BM_HIDDEN)) {
419                                         f = NULL;
420                                 }
421                                 else {
422                                         break;
423                                 }
424                         }
425                 }
426                 /* Last attempt: try to find any selected face */
427                 if (f == NULL) {
428                         BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
429                                 if (BM_TestHFlag(f, BM_SELECT)) {
430                                         break;
431                                 }
432                         }
433                 }
434                 return f; /* can still be null */
435         }
436         return NULL;
437 }
438
439 /* Generic way to get data from an EditSelection type
440  * These functions were written to be used by the Modifier widget
441  * when in Rotate about active mode, but can be used anywhere.
442  *
443  * - EM_editselection_center
444  * - EM_editselection_normal
445  * - EM_editselection_plane
446  */
447 void BM_editselection_center(BMesh *bm, float r_center[3], BMEditSelection *ese)
448 {
449         if (ese->htype == BM_VERT) {
450                 BMVert *eve = ese->data;
451                 copy_v3_v3(r_center, eve->co);
452         }
453         else if (ese->htype == BM_EDGE) {
454                 BMEdge *eed = ese->data;
455                 add_v3_v3v3(r_center, eed->v1->co, eed->v2->co);
456                 mul_v3_fl(r_center, 0.5);
457         }
458         else if (ese->htype == BM_FACE) {
459                 BMFace *efa = ese->data;
460                 BM_Compute_Face_CenterBounds(bm, efa, r_center);
461         }
462 }
463
464 void BM_editselection_normal(float r_normal[3], BMEditSelection *ese)
465 {
466         if (ese->htype == BM_VERT) {
467                 BMVert *eve = ese->data;
468                 copy_v3_v3(r_normal, eve->no);
469         }
470         else if (ese->htype == BM_EDGE) {
471                 BMEdge *eed = ese->data;
472                 float plane[3]; /* need a plane to correct the normal */
473                 float vec[3]; /* temp vec storage */
474                 
475                 add_v3_v3v3(r_normal, eed->v1->no, eed->v2->no);
476                 sub_v3_v3v3(plane, eed->v2->co, eed->v1->co);
477                 
478                 /* the 2 vertex normals will be close but not at rightangles to the edge
479                  * for rotate about edge we want them to be at right angles, so we need to
480                  * do some extra colculation to correct the vert normals,
481                  * we need the plane for this */
482                 cross_v3_v3v3(vec, r_normal, plane);
483                 cross_v3_v3v3(r_normal, plane, vec);
484                 normalize_v3(r_normal);
485                 
486         }
487         else if (ese->htype == BM_FACE) {
488                 BMFace *efa = ese->data;
489                 copy_v3_v3(r_normal, efa->no);
490         }
491 }
492
493 /* ref - editmesh_lib.cL:EM_editselection_plane() */
494
495 /* Calculate a plane that is rightangles to the edge/vert/faces normal
496  * also make the plane run along an axis that is related to the geometry,
497  * because this is used for the manipulators Y axis. */
498 void BM_editselection_plane(BMesh *bm, float r_plane[3], BMEditSelection *ese)
499 {
500         if (ese->htype == BM_VERT) {
501                 BMVert *eve = ese->data;
502                 float vec[3] = {0.0f, 0.0f, 0.0f};
503                 
504                 if (ese->prev) { /* use previously selected data to make a useful vertex plane */
505                         BM_editselection_center(bm, vec, ese->prev);
506                         sub_v3_v3v3(r_plane, vec, eve->co);
507                 }
508                 else {
509                         /* make a fake  plane thats at rightangles to the normal
510                          * we cant make a crossvec from a vec thats the same as the vec
511                          * unlikely but possible, so make sure if the normal is (0, 0, 1)
512                          * that vec isnt the same or in the same direction even. */
513                         if (eve->no[0] < 0.5f)          vec[0] = 1.0f;
514                         else if (eve->no[1] < 0.5f)     vec[1] = 1.0f;
515                         else                                            vec[2] = 1.0f;
516                         cross_v3_v3v3(r_plane, eve->no, vec);
517                 }
518         }
519         else if (ese->htype == BM_EDGE) {
520                 BMEdge *eed = ese->data;
521
522                 /* the plane is simple, it runs along the edge
523                  * however selecting different edges can swap the direction of the y axis.
524                  * this makes it less likely for the y axis of the manipulator
525                  * (running along the edge).. to flip less often.
526                  * at least its more pradictable */
527                 if (eed->v2->co[1] > eed->v1->co[1]) {  /* check which to do first */
528                         sub_v3_v3v3(r_plane, eed->v2->co, eed->v1->co);
529                 }
530                 else {
531                         sub_v3_v3v3(r_plane, eed->v1->co, eed->v2->co);
532                 }
533                 
534         }
535         else if (ese->htype == BM_FACE) {
536                 BMFace *efa = ese->data;
537                 float vec[3] = {0.0f, 0.0f, 0.0f};
538                 
539                 /* for now, use face normal */
540
541                 /* make a fake plane thats at rightangles to the normal
542                  * we cant make a crossvec from a vec thats the same as the vec
543                  * unlikely but possible, so make sure if the normal is (0, 0, 1)
544                  * that vec isnt the same or in the same direction even. */
545                 if (efa->len < 3) {
546                         /* crappy fallback method */
547                         if      (efa->no[0] < 0.5f)     vec[0] = 1.0f;
548                         else if (efa->no[1] < 0.5f)     vec[1] = 1.0f;
549                         else                        vec[2] = 1.0f;
550                         cross_v3_v3v3(r_plane, efa->no, vec);
551                 }
552                 else {
553                         BMVert *verts[4] = {NULL};
554
555                         BMIter_AsArray(bm, BM_VERTS_OF_FACE, efa, (void **)verts, 4);
556
557                         if (efa->len == 4) {
558                                 float vecA[3], vecB[3];
559                                 sub_v3_v3v3(vecA, verts[3]->co, verts[2]->co);
560                                 sub_v3_v3v3(vecB, verts[0]->co, verts[1]->co);
561                                 add_v3_v3v3(r_plane, vecA, vecB);
562
563                                 sub_v3_v3v3(vecA, verts[0]->co, verts[3]->co);
564                                 sub_v3_v3v3(vecB, verts[1]->co, verts[2]->co);
565                                 add_v3_v3v3(vec, vecA, vecB);
566                                 /* use the biggest edge length */
567                                 if (dot_v3v3(r_plane, r_plane) < dot_v3v3(vec, vec)) {
568                                         copy_v3_v3(r_plane, vec);
569                                 }
570                         }
571                         else {
572                                 /* BMESH_TODO (not urgent, use longest ngon edge for alignment) */
573
574                                 /* start with v1-2 */
575                                 sub_v3_v3v3(r_plane, verts[0]->co, verts[1]->co);
576
577                                 /* test the edge between v2-3, use if longer */
578                                 sub_v3_v3v3(vec, verts[1]->co, verts[2]->co);
579                                 if (dot_v3v3(r_plane, r_plane) < dot_v3v3(vec, vec))
580                                         copy_v3_v3(r_plane, vec);
581
582                                 /* test the edge between v1-3, use if longer */
583                                 sub_v3_v3v3(vec, verts[2]->co, verts[0]->co);
584                                 if (dot_v3v3(r_plane, r_plane) < dot_v3v3(vec, vec)) {
585                                         copy_v3_v3(r_plane, vec);
586                                 }
587                         }
588
589                 }
590         }
591         normalize_v3(r_plane);
592 }
593
594 static int BM_check_selection(BMesh *bm, void *data)
595 {
596         BMEditSelection *ese;
597         
598         for (ese = bm->selected.first; ese; ese = ese->next) {
599                 if (ese->data == data) {
600                         return TRUE;
601                 }
602         }
603         
604         return FALSE;
605 }
606
607 void BM_remove_selection(BMesh *bm, void *data)
608 {
609         BMEditSelection *ese;
610         for (ese = bm->selected.first; ese; ese = ese->next) {
611                 if (ese->data == data) {
612                         BLI_freelinkN(&(bm->selected), ese);
613                         break;
614                 }
615         }
616 }
617
618 void BM_clear_selection_history(BMesh *bm)
619 {
620         BLI_freelistN(&bm->selected);
621         bm->selected.first = bm->selected.last = NULL;
622 }
623
624 void BM_store_selection(BMesh *bm, void *data)
625 {
626         BMEditSelection *ese;
627         if (!BM_check_selection(bm, data)) {
628                 ese = (BMEditSelection *) MEM_callocN(sizeof(BMEditSelection), "BMEdit Selection");
629                 ese->htype = ((BMHeader *)data)->htype;
630                 ese->data = data;
631                 BLI_addtail(&(bm->selected), ese);
632         }
633 }
634
635 void BM_validate_selections(BMesh *bm)
636 {
637         BMEditSelection *ese, *nextese;
638
639         ese = bm->selected.first;
640
641         while (ese) {
642                 nextese = ese->next;
643                 if (!BM_TestHFlag(ese->data, BM_SELECT)) {
644                         BLI_freelinkN(&(bm->selected), ese);
645                 }
646                 ese = nextese;
647         }
648 }
649
650 void BM_clear_flag_all(BMesh *bm, const char hflag)
651 {
652         const char iter_types[3] = {BM_VERTS_OF_MESH,
653                                     BM_EDGES_OF_MESH,
654                                     BM_FACES_OF_MESH};
655         BMIter iter;
656         BMHeader *ele;
657         int i;
658
659         if (hflag & BM_SELECT) {
660                 BM_clear_selection_history(bm);
661         }
662
663         for (i = 0; i < 3; i++) {
664                 ele = BMIter_New(&iter, bm, iter_types[i], NULL);
665                 for ( ; ele; ele = BMIter_Step(&iter)) {
666                         if (hflag & BM_SELECT) BM_Select(bm, ele, FALSE);
667                         BM_ClearHFlag(ele, hflag);
668                 }
669         }
670 }
671
672
673 /***************** Mesh Hiding stuff *********** */
674
675 #define SETHIDE(ele) hide ? BM_SetHFlag(ele, BM_HIDDEN) : BM_ClearHFlag(ele, BM_HIDDEN);
676
677 static void vert_flush_hide(BMesh *bm, BMVert *v)
678 {
679         BMIter iter;
680         BMEdge *e;
681         int hide = 1;
682
683         BM_ITER(e, &iter, bm, BM_EDGES_OF_VERT, v) {
684                 hide = hide && BM_TestHFlag(e, BM_HIDDEN);
685         }
686
687         SETHIDE(v);
688 }
689
690 static void edge_flush_hide(BMesh *bm, BMEdge *e)
691 {
692         BMIter iter;
693         BMFace *f;
694         int hide = 1;
695
696         BM_ITER(f, &iter, bm, BM_FACES_OF_EDGE, e) {
697                 hide = hide && BM_TestHFlag(f, BM_HIDDEN);
698         }
699
700         SETHIDE(e);
701 }
702
703 void BM_Hide_Vert(BMesh *bm, BMVert *v, int hide)
704 {
705         /* vert hiding: vert + surrounding edges and faces */
706         BMIter iter, fiter;
707         BMEdge *e;
708         BMFace *f;
709
710         SETHIDE(v);
711
712         BM_ITER(e, &iter, bm, BM_EDGES_OF_VERT, v) {
713                 SETHIDE(e);
714
715                 BM_ITER(f, &fiter, bm, BM_FACES_OF_EDGE, e) {
716                         SETHIDE(f);
717                 }
718         }
719 }
720
721 void BM_Hide_Edge(BMesh *bm, BMEdge *e, int hide)
722 {
723         BMIter iter;
724         BMFace *f;
725         /* BMVert *v; */
726
727         /* edge hiding: faces around the edge */
728         BM_ITER(f, &iter, bm, BM_FACES_OF_EDGE, e) {
729                 SETHIDE(f);
730         }
731         
732         SETHIDE(e);
733
734         /* hide vertices if necassary */
735         vert_flush_hide(bm, e->v1);
736         vert_flush_hide(bm, e->v2);
737 }
738
739 void BM_Hide_Face(BMesh *bm, BMFace *f, int hide)
740 {
741         BMIter iter;
742         BMLoop *l;
743
744         SETHIDE(f);
745
746         BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) {
747                 edge_flush_hide(bm, l->e);
748         }
749
750         BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) {
751                 vert_flush_hide(bm, l->v);
752         }
753 }
754
755 void BM_Hide(BMesh *bm, void *element, int hide)
756 {
757         BMHeader *h = element;
758
759         /* Follow convention of always deselecting before
760          * hiding an element */
761         if (hide) {
762                 BM_Select(bm, element, FALSE);
763         }
764
765         switch (h->htype) {
766                 case BM_VERT:
767                         BM_Hide_Vert(bm, element, hide);
768                         break;
769                 case BM_EDGE:
770                         BM_Hide_Edge(bm, element, hide);
771                         break;
772                 case BM_FACE:
773                         BM_Hide_Face(bm, element, hide);
774                         break;
775         }
776 }