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