diff options
Diffstat (limited to 'source/blender/bmesh/intern/bmesh_marking.c')
-rw-r--r-- | source/blender/bmesh/intern/bmesh_marking.c | 910 |
1 files changed, 910 insertions, 0 deletions
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c new file mode 100644 index 00000000000..8a8ccb5efb1 --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_marking.c @@ -0,0 +1,910 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Joseph Eagar, Geoffrey Bantle, Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/bmesh/intern/bmesh_marking.c + * \ingroup bmesh + * + * Selection routines for bmesh structures. + * This is actually all old code ripped from + * editmesh_lib.c and slightly modified to work + * for bmesh's. This also means that it has some + * of the same problems.... something that + * that should be addressed eventually. + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_scene_types.h" + +#include "BLI_math.h" +#include "BLI_listbase.h" + +#include "bmesh.h" + + +/* + * BMESH SELECTMODE FLUSH + * + * Makes sure to flush selections + * 'upwards' (ie: all verts of an edge + * selects the edge and so on). This + * should only be called by system and not + * tool authors. + * + */ + +static void recount_totsels(BMesh *bm) +{ + BMIter iter; + BMHeader *ele; + const char iter_types[3] = {BM_VERTS_OF_MESH, + BM_EDGES_OF_MESH, + BM_FACES_OF_MESH}; + int *tots[3]; + int i; + + /* recount (tot * sel) variables */ + bm->totvertsel = bm->totedgesel = bm->totfacesel = 0; + tots[0] = &bm->totvertsel; + tots[1] = &bm->totedgesel; + tots[2] = &bm->totfacesel; + + for (i = 0; i < 3; i++) { + ele = BM_iter_new(&iter, bm, iter_types[i], NULL); + for ( ; ele; ele = BM_iter_step(&iter)) { + if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) *tots[i] += 1; + } + } +} + +void BM_mesh_select_mode_flush(BMesh *bm) +{ + BMEdge *e; + BMLoop *l_iter; + BMLoop *l_first; + BMFace *f; + + BMIter edges; + BMIter faces; + + int ok; + + if (bm->selectmode & SCE_SELECT_VERTEX) { + for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges)) { + if (BM_elem_flag_test(e->v1, BM_ELEM_SELECT) && + BM_elem_flag_test(e->v2, BM_ELEM_SELECT) && + !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) + { + BM_elem_flag_enable(e, BM_ELEM_SELECT); + } + else { + BM_elem_flag_disable(e, BM_ELEM_SELECT); + } + } + for (f = BM_iter_new(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BM_iter_step(&faces)) { + ok = TRUE; + if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (!BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) { + ok = FALSE; + break; + } + } while ((l_iter = l_iter->next) != l_first); + } + else { + ok = FALSE; + } + + if (ok) { + BM_elem_flag_enable(f, BM_ELEM_SELECT); + } + else { + BM_elem_flag_disable(f, BM_ELEM_SELECT); + } + } + } + else if (bm->selectmode & SCE_SELECT_EDGE) { + for (f = BM_iter_new(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BM_iter_step(&faces)) { + ok = TRUE; + if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (!BM_elem_flag_test(&(l_iter->e->head), BM_ELEM_SELECT)) { + ok = FALSE; + break; + } + } while ((l_iter = l_iter->next) != l_first); + } + else { + ok = FALSE; + } + + if (ok) { + BM_elem_flag_enable(f, BM_ELEM_SELECT); + } + else { + BM_elem_flag_disable(f, BM_ELEM_SELECT); + } + } + } + + /* Remove any deselected elements from the BMEditSelection */ + BM_select_history_validate(bm); + + recount_totsels(bm); +} + +/* BMESH NOTE: matches EM_deselect_flush() behavior from trunk */ +void BM_mesh_deselect_flush(BMesh *bm) +{ + BMEdge *e; + BMLoop *l_iter; + BMLoop *l_first; + BMFace *f; + + BMIter edges; + BMIter faces; + + int ok; + + for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges)) { + if (!(BM_elem_flag_test(e->v1, BM_ELEM_SELECT) && + BM_elem_flag_test(e->v2, BM_ELEM_SELECT) && + !BM_elem_flag_test(e, BM_ELEM_HIDDEN))) + { + BM_elem_flag_disable(e, BM_ELEM_SELECT); + } + } + + for (f = BM_iter_new(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BM_iter_step(&faces)) { + ok = TRUE; + if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (!BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) { + ok = FALSE; + break; + } + } while ((l_iter = l_iter->next) != l_first); + } + else { + ok = FALSE; + } + + if (ok == FALSE) { + BM_elem_flag_disable(f, BM_ELEM_SELECT); + } + } + + /* Remove any deselected elements from the BMEditSelection */ + BM_select_history_validate(bm); + + recount_totsels(bm); +} + + +/* BMESH NOTE: matches EM_select_flush() behavior from trunk */ +void BM_mesh_select_flush(BMesh *bm) +{ + BMEdge *e; + BMLoop *l_iter; + BMLoop *l_first; + BMFace *f; + + BMIter edges; + BMIter faces; + + int ok; + + for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges)) { + if (BM_elem_flag_test(e->v1, BM_ELEM_SELECT) && + BM_elem_flag_test(e->v2, BM_ELEM_SELECT) && + !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) + { + BM_elem_flag_enable(e, BM_ELEM_SELECT); + } + } + + for (f = BM_iter_new(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BM_iter_step(&faces)) { + ok = TRUE; + if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (!BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) { + ok = FALSE; + break; + } + } while ((l_iter = l_iter->next) != l_first); + } + else { + ok = FALSE; + } + + if (ok) { + BM_elem_flag_enable(f, BM_ELEM_SELECT); + } + } + + recount_totsels(bm); +} + +/* + * BMESH SELECT VERT + * + * Changes selection state of a single vertex + * in a mesh + * + */ + +void BM_vert_select_set(BMesh *bm, BMVert *v, int select) +{ + /* BMIter iter; */ + /* BMEdge *e; */ + + if (BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { + return; + } + + if (select) { + if (!BM_elem_flag_test(v, BM_ELEM_SELECT)) { + bm->totvertsel += 1; + BM_elem_flag_enable(v, BM_ELEM_SELECT); + } + } + else { + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { + bm->totvertsel -= 1; + BM_elem_flag_disable(v, BM_ELEM_SELECT); + } + } +} + +/* + * BMESH SELECT EDGE + * + * Changes selection state of a single edge + * in a mesh. + * + */ + +void BM_edge_select_set(BMesh *bm, BMEdge *e, int select) +{ + if (BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { + return; + } + + if (select) { + if (!BM_elem_flag_test(e, BM_ELEM_SELECT)) bm->totedgesel += 1; + + BM_elem_flag_enable(&(e->head), BM_ELEM_SELECT); + BM_elem_select_set(bm, e->v1, TRUE); + BM_elem_select_set(bm, e->v2, TRUE); + } + else { + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) bm->totedgesel -= 1; + BM_elem_flag_disable(&(e->head), BM_ELEM_SELECT); + + if ( bm->selectmode == SCE_SELECT_EDGE || + bm->selectmode == SCE_SELECT_FACE || + bm->selectmode == (SCE_SELECT_EDGE | SCE_SELECT_FACE)) + { + + BMIter iter; + BMVert *verts[2] = {e->v1, e->v2}; + BMEdge *e2; + int i; + + for (i = 0; i < 2; i++) { + int deselect = 1; + + for (e2 = BM_iter_new(&iter, bm, BM_EDGES_OF_VERT, verts[i]); e2; e2 = BM_iter_step(&iter)) { + if (e2 == e) { + continue; + } + + if (BM_elem_flag_test(e2, BM_ELEM_SELECT)) { + deselect = 0; + break; + } + } + + if (deselect) BM_vert_select_set(bm, verts[i], FALSE); + } + } + else { + BM_elem_select_set(bm, e->v1, FALSE); + BM_elem_select_set(bm, e->v2, FALSE); + } + + } +} + +/* + * + * BMESH SELECT FACE + * + * Changes selection state of a single + * face in a mesh. + * + */ + +void BM_face_select_set(BMesh *bm, BMFace *f, int select) +{ + BMLoop *l_iter; + BMLoop *l_first; + + if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + return; + } + + if (select) { + if (!BM_elem_flag_test(f, BM_ELEM_SELECT)) { + bm->totfacesel++; + } + + BM_elem_flag_enable(&(f->head), BM_ELEM_SELECT); + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BM_vert_select_set(bm, l_iter->v, TRUE); + BM_edge_select_set(bm, l_iter->e, TRUE); + } while ((l_iter = l_iter->next) != l_first); + } + else { + BMIter liter; + BMLoop *l; + + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) bm->totfacesel -= 1; + BM_elem_flag_disable(&(f->head), BM_ELEM_SELECT); + + /* flush down to edges */ + BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) { + BMIter fiter; + BMFace *f2; + BM_ITER(f2, &fiter, bm, BM_FACES_OF_EDGE, l->e) { + if (BM_elem_flag_test(f2, BM_ELEM_SELECT)) + break; + } + + if (!f2) + { + BM_elem_select_set(bm, l->e, FALSE); + } + } + + /* flush down to verts */ + BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) { + BMIter eiter; + BMEdge *e; + BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, l->v) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) + break; + } + + if (!e) { + BM_elem_select_set(bm, l->v, FALSE); + } + } + } +} + +/* + * BMESH SELECTMODE SET + * + * Sets the selection mode for the bmesh + * + */ + +void BM_select_mode_set(BMesh *bm, int selectmode) +{ + BMVert *v; + BMEdge *e; + BMFace *f; + + BMIter verts; + BMIter edges; + BMIter faces; + + bm->selectmode = selectmode; + + if (bm->selectmode & SCE_SELECT_VERTEX) { + for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges)) + BM_elem_flag_disable(e, 0); + for (f = BM_iter_new(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BM_iter_step(&faces)) + BM_elem_flag_disable(f, 0); + BM_mesh_select_mode_flush(bm); + } + else if (bm->selectmode & SCE_SELECT_EDGE) { + for (v = BM_iter_new(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BM_iter_step(&verts)) + BM_elem_flag_disable(v, 0); + for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges)) { + if (BM_elem_flag_test(&(e->head), BM_ELEM_SELECT)) { + BM_edge_select_set(bm, e, TRUE); + } + } + BM_mesh_select_mode_flush(bm); + } + else if (bm->selectmode & SCE_SELECT_FACE) { + for (e = BM_iter_new(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BM_iter_step(&edges)) + BM_elem_flag_disable(e, 0); + for (f = BM_iter_new(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BM_iter_step(&faces)) { + if (BM_elem_flag_test(&(f->head), BM_ELEM_SELECT)) { + BM_face_select_set(bm, f, TRUE); + } + } + BM_mesh_select_mode_flush(bm); + } +} + + +int BM_mesh_count_flag(struct BMesh *bm, const char htype, const char hflag, int respecthide) +{ + BMHeader *head; + BMIter iter; + int tot = 0; + + if (htype & BM_VERT) { + for (head = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL); head; head = BM_iter_step(&iter)) { + if (respecthide && BM_elem_flag_test(head, BM_ELEM_HIDDEN)) continue; + if (BM_elem_flag_test(head, hflag)) tot++; + } + } + if (htype & BM_EDGE) { + for (head = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, NULL); head; head = BM_iter_step(&iter)) { + if (respecthide && BM_elem_flag_test(head, BM_ELEM_HIDDEN)) continue; + if (BM_elem_flag_test(head, hflag)) tot++; + } + } + if (htype & BM_FACE) { + for (head = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, NULL); head; head = BM_iter_step(&iter)) { + if (respecthide && BM_elem_flag_test(head, BM_ELEM_HIDDEN)) continue; + if (BM_elem_flag_test(head, hflag)) tot++; + } + } + + return tot; +} + +/* note: by design, this will not touch the editselection history stuff */ +void BM_elem_select_set(struct BMesh *bm, void *element, int select) +{ + BMHeader *head = element; + + if (head->htype == BM_VERT) BM_vert_select_set(bm, (BMVert *)element, select); + else if (head->htype == BM_EDGE) BM_edge_select_set(bm, (BMEdge *)element, select); + else if (head->htype == BM_FACE) BM_face_select_set(bm, (BMFace *)element, select); +} + +/* this replaces the active flag used in uv/face mode */ +void BM_active_face_set(BMesh *bm, BMFace *efa) +{ + bm->act_face = efa; +} + +BMFace *BM_active_face_get(BMesh *bm, int sloppy) +{ + if (bm->act_face) { + return bm->act_face; + } + else if (sloppy) { + BMIter iter; + BMFace *f = NULL; + BMEditSelection *ese; + + /* Find the latest non-hidden face from the BMEditSelection */ + ese = bm->selected.last; + for ( ; ese; ese = ese->prev) { + if (ese->htype == BM_FACE) { + f = (BMFace *)ese->data; + + if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + f = NULL; + } + else { + break; + } + } + } + /* Last attempt: try to find any selected face */ + if (f == NULL) { + BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + break; + } + } + } + return f; /* can still be null */ + } + return NULL; +} + +/* Generic way to get data from an EditSelection type + * These functions were written to be used by the Modifier widget + * when in Rotate about active mode, but can be used anywhere. + * + * - EM_editselection_center + * - EM_editselection_normal + * - EM_editselection_plane + */ +void BM_editselection_center(BMesh *bm, float r_center[3], BMEditSelection *ese) +{ + if (ese->htype == BM_VERT) { + BMVert *eve = ese->data; + copy_v3_v3(r_center, eve->co); + } + else if (ese->htype == BM_EDGE) { + BMEdge *eed = ese->data; + add_v3_v3v3(r_center, eed->v1->co, eed->v2->co); + mul_v3_fl(r_center, 0.5); + } + else if (ese->htype == BM_FACE) { + BMFace *efa = ese->data; + BM_face_center_bounds_calc(bm, efa, r_center); + } +} + +void BM_editselection_normal(float r_normal[3], BMEditSelection *ese) +{ + if (ese->htype == BM_VERT) { + BMVert *eve = ese->data; + copy_v3_v3(r_normal, eve->no); + } + else if (ese->htype == BM_EDGE) { + BMEdge *eed = ese->data; + float plane[3]; /* need a plane to correct the normal */ + float vec[3]; /* temp vec storage */ + + add_v3_v3v3(r_normal, eed->v1->no, eed->v2->no); + sub_v3_v3v3(plane, eed->v2->co, eed->v1->co); + + /* the 2 vertex normals will be close but not at rightangles to the edge + * for rotate about edge we want them to be at right angles, so we need to + * do some extra colculation to correct the vert normals, + * we need the plane for this */ + cross_v3_v3v3(vec, r_normal, plane); + cross_v3_v3v3(r_normal, plane, vec); + normalize_v3(r_normal); + + } + else if (ese->htype == BM_FACE) { + BMFace *efa = ese->data; + copy_v3_v3(r_normal, efa->no); + } +} + +/* ref - editmesh_lib.cL:EM_editselection_plane() */ + +/* Calculate a plane that is rightangles to the edge/vert/faces normal + * also make the plane run along an axis that is related to the geometry, + * because this is used for the manipulators Y axis. */ +void BM_editselection_plane(BMesh *bm, float r_plane[3], BMEditSelection *ese) +{ + if (ese->htype == BM_VERT) { + BMVert *eve = ese->data; + float vec[3] = {0.0f, 0.0f, 0.0f}; + + if (ese->prev) { /* use previously selected data to make a useful vertex plane */ + BM_editselection_center(bm, vec, ese->prev); + sub_v3_v3v3(r_plane, vec, eve->co); + } + else { + /* make a fake plane thats at rightangles to the normal + * we cant make a crossvec from a vec thats the same as the vec + * unlikely but possible, so make sure if the normal is (0, 0, 1) + * that vec isnt the same or in the same direction even. */ + if (eve->no[0] < 0.5f) vec[0] = 1.0f; + else if (eve->no[1] < 0.5f) vec[1] = 1.0f; + else vec[2] = 1.0f; + cross_v3_v3v3(r_plane, eve->no, vec); + } + } + else if (ese->htype == BM_EDGE) { + BMEdge *eed = ese->data; + + /* the plane is simple, it runs along the edge + * however selecting different edges can swap the direction of the y axis. + * this makes it less likely for the y axis of the manipulator + * (running along the edge).. to flip less often. + * at least its more pradictable */ + if (eed->v2->co[1] > eed->v1->co[1]) { /* check which to do first */ + sub_v3_v3v3(r_plane, eed->v2->co, eed->v1->co); + } + else { + sub_v3_v3v3(r_plane, eed->v1->co, eed->v2->co); + } + + } + else if (ese->htype == BM_FACE) { + BMFace *efa = ese->data; + float vec[3] = {0.0f, 0.0f, 0.0f}; + + /* for now, use face normal */ + + /* make a fake plane thats at rightangles to the normal + * we cant make a crossvec from a vec thats the same as the vec + * unlikely but possible, so make sure if the normal is (0, 0, 1) + * that vec isnt the same or in the same direction even. */ + if (efa->len < 3) { + /* crappy fallback method */ + if (efa->no[0] < 0.5f) vec[0] = 1.0f; + else if (efa->no[1] < 0.5f) vec[1] = 1.0f; + else vec[2] = 1.0f; + cross_v3_v3v3(r_plane, efa->no, vec); + } + else { + BMVert *verts[4] = {NULL}; + + BM_iter_as_array(bm, BM_VERTS_OF_FACE, efa, (void **)verts, 4); + + if (efa->len == 4) { + float vecA[3], vecB[3]; + sub_v3_v3v3(vecA, verts[3]->co, verts[2]->co); + sub_v3_v3v3(vecB, verts[0]->co, verts[1]->co); + add_v3_v3v3(r_plane, vecA, vecB); + + sub_v3_v3v3(vecA, verts[0]->co, verts[3]->co); + sub_v3_v3v3(vecB, verts[1]->co, verts[2]->co); + add_v3_v3v3(vec, vecA, vecB); + /* use the biggest edge length */ + if (dot_v3v3(r_plane, r_plane) < dot_v3v3(vec, vec)) { + copy_v3_v3(r_plane, vec); + } + } + else { + /* BMESH_TODO (not urgent, use longest ngon edge for alignment) */ + + /* start with v1-2 */ + sub_v3_v3v3(r_plane, verts[0]->co, verts[1]->co); + + /* test the edge between v2-3, use if longer */ + sub_v3_v3v3(vec, verts[1]->co, verts[2]->co); + if (dot_v3v3(r_plane, r_plane) < dot_v3v3(vec, vec)) + copy_v3_v3(r_plane, vec); + + /* test the edge between v1-3, use if longer */ + sub_v3_v3v3(vec, verts[2]->co, verts[0]->co); + if (dot_v3v3(r_plane, r_plane) < dot_v3v3(vec, vec)) { + copy_v3_v3(r_plane, vec); + } + } + + } + } + normalize_v3(r_plane); +} + +int BM_select_history_check(BMesh *bm, void *data) +{ + BMEditSelection *ese; + + for (ese = bm->selected.first; ese; ese = ese->next) { + if (ese->data == data) { + return TRUE; + } + } + + return FALSE; +} + +void BM_select_history_remove(BMesh *bm, void *data) +{ + BMEditSelection *ese; + for (ese = bm->selected.first; ese; ese = ese->next) { + if (ese->data == data) { + BLI_freelinkN(&(bm->selected), ese); + break; + } + } +} + +void BM_select_history_clear(BMesh *bm) +{ + BLI_freelistN(&bm->selected); + bm->selected.first = bm->selected.last = NULL; +} + +void BM_select_history_store(BMesh *bm, void *data) +{ + BMEditSelection *ese; + if (!BM_select_history_check(bm, data)) { + ese = (BMEditSelection *) MEM_callocN(sizeof(BMEditSelection), "BMEdit Selection"); + ese->htype = ((BMHeader *)data)->htype; + ese->data = data; + BLI_addtail(&(bm->selected), ese); + } +} + +void BM_select_history_validate(BMesh *bm) +{ + BMEditSelection *ese, *nextese; + + ese = bm->selected.first; + + while (ese) { + nextese = ese->next; + if (!BM_elem_flag_test(ese->data, BM_ELEM_SELECT)) { + BLI_freelinkN(&(bm->selected), ese); + } + ese = nextese; + } +} + +void BM_mesh_elem_flag_disable_all(BMesh *bm, const char htype, const char hflag) +{ + const char iter_types[3] = {BM_VERTS_OF_MESH, + BM_EDGES_OF_MESH, + BM_FACES_OF_MESH}; + BMIter iter; + BMHeader *ele; + int i; + + if (hflag & BM_ELEM_SELECT) { + BM_select_history_clear(bm); + } + + for (i = 0; i < 3; i++) { + if (htype & iter_types[i]) { + ele = BM_iter_new(&iter, bm, iter_types[i], NULL); + for ( ; ele; ele = BM_iter_step(&iter)) { + if (hflag & BM_ELEM_SELECT) { + BM_elem_select_set(bm, ele, FALSE); + } + BM_elem_flag_disable(ele, hflag); + } + } + } +} + +void BM_mesh_elem_flag_enable_all(BMesh *bm, const char htype, const char hflag) +{ + const char iter_types[3] = {BM_VERTS_OF_MESH, + BM_EDGES_OF_MESH, + BM_FACES_OF_MESH}; + BMIter iter; + BMHeader *ele; + int i; + + if (hflag & BM_ELEM_SELECT) { + BM_select_history_clear(bm); + } + + for (i = 0; i < 3; i++) { + if (htype & iter_types[i]) { + ele = BM_iter_new(&iter, bm, iter_types[i], NULL); + for ( ; ele; ele = BM_iter_step(&iter)) { + if (hflag & BM_ELEM_SELECT) { + BM_elem_select_set(bm, ele, TRUE); + } + BM_elem_flag_enable(ele, hflag); + } + } + } +} + +/***************** Mesh Hiding stuff *********** */ + +#define BM_ELEM_HIDE_SET(ele, hide) \ + (hide) ? BM_elem_flag_enable(ele, BM_ELEM_HIDDEN) : BM_elem_flag_disable(ele, BM_ELEM_HIDDEN); + +static void vert_flush_hide_set(BMesh *bm, BMVert *v) +{ + BMIter iter; + BMEdge *e; + int hide = TRUE; + + BM_ITER(e, &iter, bm, BM_EDGES_OF_VERT, v) { + hide = hide && BM_elem_flag_test(e, BM_ELEM_HIDDEN); + } + + BM_ELEM_HIDE_SET(v, hide); +} + +static void edge_flush_hide(BMesh *bm, BMEdge *e) +{ + BMIter iter; + BMFace *f; + int hide = TRUE; + + BM_ITER(f, &iter, bm, BM_FACES_OF_EDGE, e) { + hide = hide && BM_elem_flag_test(f, BM_ELEM_HIDDEN); + } + + BM_ELEM_HIDE_SET(e, hide); +} + +void BM_vert_hide_set(BMesh *bm, BMVert *v, int hide) +{ + /* vert hiding: vert + surrounding edges and faces */ + BMIter iter, fiter; + BMEdge *e; + BMFace *f; + + BM_ELEM_HIDE_SET(v, hide); + + BM_ITER(e, &iter, bm, BM_EDGES_OF_VERT, v) { + BM_ELEM_HIDE_SET(e, hide); + + BM_ITER(f, &fiter, bm, BM_FACES_OF_EDGE, e) { + BM_ELEM_HIDE_SET(f, hide); + } + } +} + +void BM_edge_hide_set(BMesh *bm, BMEdge *e, int hide) +{ + BMIter iter; + BMFace *f; + /* BMVert *v; */ + + /* edge hiding: faces around the edge */ + BM_ITER(f, &iter, bm, BM_FACES_OF_EDGE, e) { + BM_ELEM_HIDE_SET(f, hide); + } + + BM_ELEM_HIDE_SET(e, hide); + + /* hide vertices if necassary */ + vert_flush_hide_set(bm, e->v1); + vert_flush_hide_set(bm, e->v2); +} + +void BM_face_hide_set(BMesh *bm, BMFace *f, int hide) +{ + BMIter iter; + BMLoop *l; + + BM_ELEM_HIDE_SET(f, hide); + + BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) { + edge_flush_hide(bm, l->e); + } + + BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) { + vert_flush_hide_set(bm, l->v); + } +} + +#undef BM_ELEM_HIDE_SET + + +void BM_elem_hide_set(BMesh *bm, void *element, int hide) +{ + BMHeader *h = element; + + /* Follow convention of always deselecting before + * hiding an element */ + if (hide) { + BM_elem_select_set(bm, element, FALSE); + } + + switch (h->htype) { + case BM_VERT: + BM_vert_hide_set(bm, element, hide); + break; + case BM_EDGE: + BM_edge_hide_set(bm, element, hide); + break; + case BM_FACE: + BM_face_hide_set(bm, element, hide); + break; + } +} |