710 lines
16 KiB
C
710 lines
16 KiB
C
#include "MEM_guardedalloc.h"
|
|
|
|
#include "BKE_utildefines.h"
|
|
|
|
#include "BLI_math.h"
|
|
#include "BLI_blenlib.h"
|
|
#include "BLI_array.h"
|
|
|
|
#include "bmesh.h"
|
|
#include "bmesh_private.h"
|
|
|
|
#include <string.h>
|
|
|
|
/*
|
|
* BM_MARK.C
|
|
*
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
|
|
/*
|
|
* 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;
|
|
int 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 = BMIter_New(&iter, bm, types[i], NULL);
|
|
for ( ; ele; ele=BMIter_Step(&iter)) {
|
|
if (BM_TestHFlag(ele, BM_SELECT)) *tots[i] += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
void BM_SelectMode_Flush(BMesh *bm)
|
|
{
|
|
BMEdge *e;
|
|
BMLoop *l;
|
|
BMFace *f;
|
|
|
|
BMIter edges;
|
|
BMIter faces;
|
|
|
|
int totsel;
|
|
|
|
if(bm->selectmode & SCE_SELECT_VERTEX) {
|
|
for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm ); e; e= BMIter_Step(&edges)) {
|
|
if(BM_TestHFlag(e->v1, BM_SELECT) && BM_TestHFlag(e->v2, BM_SELECT)) BM_SetHFlag(e, BM_SELECT);
|
|
else BM_ClearHFlag(e, BM_SELECT);
|
|
}
|
|
for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f= BMIter_Step(&faces)) {
|
|
totsel = 0;
|
|
l=(BMLoop*) bm_firstfaceloop(f);
|
|
do{
|
|
if(BM_TestHFlag(l->v, BM_SELECT))
|
|
totsel++;
|
|
l = ((BMLoop*)(l->next));
|
|
} while(l != bm_firstfaceloop(f));
|
|
|
|
if(totsel == f->len)
|
|
BM_SetHFlag(f, BM_SELECT);
|
|
else
|
|
BM_ClearHFlag(f, BM_SELECT);
|
|
}
|
|
}
|
|
else if(bm->selectmode & SCE_SELECT_EDGE) {
|
|
for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f= BMIter_Step(&faces)) {
|
|
totsel = 0;
|
|
l=(BMLoop*) bm_firstfaceloop(f);
|
|
do{
|
|
if(bmesh_test_sysflag(&(l->e->head), BM_SELECT))
|
|
totsel++;
|
|
l = ((BMLoop*)(l->next));
|
|
}while(l!=bm_firstfaceloop(f));
|
|
|
|
if(totsel == f->len)
|
|
BM_SetHFlag(f, BM_SELECT);
|
|
else
|
|
BM_ClearHFlag(f, BM_SELECT);
|
|
}
|
|
}
|
|
|
|
recount_totsels(bm);
|
|
}
|
|
|
|
/*
|
|
* BMESH SELECT VERT
|
|
*
|
|
* Changes selection state of a single vertex
|
|
* in a mesh
|
|
*
|
|
*/
|
|
|
|
void BM_Select_Vert(BMesh *bm, BMVert *v, int select)
|
|
{
|
|
BMIter iter;
|
|
BMEdge *e;
|
|
|
|
if(select) {
|
|
if (!BM_TestHFlag(v, BM_SELECT)) bm->totvertsel += 1;
|
|
BM_SetHFlag(v, BM_SELECT);
|
|
} else {
|
|
if (BM_TestHFlag(v, BM_SELECT)) bm->totvertsel -= 1;
|
|
BM_ClearHFlag(v, BM_SELECT);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* BMESH SELECT EDGE
|
|
*
|
|
* Changes selection state of a single edge
|
|
* in a mesh. Note that this may not be
|
|
* 100 percent reliable.
|
|
*
|
|
*/
|
|
|
|
void BM_Select_Edge(BMesh *bm, BMEdge *e, int select)
|
|
{
|
|
int candesel;
|
|
int testiso = 1;
|
|
|
|
/*I might move this logic to editors/mesh/bmesh_select.c, where it'd be invoked
|
|
by the selection tools. in that case, we'd still retain the checks
|
|
for if an edge's verts can be deselected.*/
|
|
|
|
/*ensure vert selections are valid, only if not in a multiselect
|
|
mode that shares SCE_SELECT_VERT*/
|
|
switch (bm->selectmode) {
|
|
case SCE_SELECT_VERTEX:
|
|
case SCE_SELECT_EDGE:
|
|
case SCE_SELECT_FACE:
|
|
case SCE_SELECT_EDGE|SCE_SELECT_FACE:
|
|
testiso = 1;
|
|
break;
|
|
default:
|
|
testiso = 0;
|
|
break;
|
|
}
|
|
|
|
if (testiso && !select) {
|
|
BMIter eiter;
|
|
BMEdge *e2;
|
|
int i;
|
|
|
|
for (i=0; i<2; i++) {
|
|
candesel = 1;
|
|
e2 = BMIter_New(&eiter, bm, BM_EDGES_OF_VERT, !i?e->v1:e->v2);
|
|
for (; e2; e2=BMIter_Step(&eiter)) {
|
|
if (e2 == e) continue;
|
|
if (BM_TestHFlag(e2, BM_SELECT)) {
|
|
candesel = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (candesel) BM_Select_Vert(bm, !i?e->v1:e->v2, 0);
|
|
}
|
|
}
|
|
|
|
if(select) {
|
|
if (!BM_TestHFlag(e, BM_SELECT)) bm->totedgesel += 1;
|
|
|
|
BM_SetHFlag(&(e->head), BM_SELECT);
|
|
BM_Select(bm, e->v1, 1);
|
|
BM_Select(bm, e->v2, 1);
|
|
}
|
|
else{
|
|
if (BM_TestHFlag(e, BM_SELECT)) bm->totedgesel -= 1;
|
|
|
|
BM_ClearHFlag(&(e->head), BM_SELECT);
|
|
}
|
|
}
|
|
|
|
/*
|
|
*
|
|
* BMESH SELECT FACE
|
|
*
|
|
* Changes selection state of a single
|
|
* face in a mesh. This (might) suffer
|
|
* from same problems as edge select
|
|
* code...
|
|
*
|
|
*/
|
|
|
|
void BM_Select_Face(BMesh *bm, BMFace *f, int select)
|
|
{
|
|
BMLoop *l;
|
|
|
|
if(select){
|
|
if (!BM_TestHFlag(f, BM_SELECT)) bm->totfacesel += 1;
|
|
|
|
BM_SetHFlag(&(f->head), BM_SELECT);
|
|
l=(BMLoop*) bm_firstfaceloop(f);
|
|
do{
|
|
BM_Select_Vert(bm, l->v, 1);
|
|
BM_Select_Edge(bm, l->e, 1);
|
|
l = ((BMLoop*)(l->next));
|
|
}while(l != bm_firstfaceloop(f));
|
|
}
|
|
else{
|
|
BMIter liter, fiter, eiter;
|
|
BMFace *f2;
|
|
BMLoop *l;
|
|
BMEdge *e;
|
|
|
|
if (BM_TestHFlag(f, BM_SELECT)) bm->totfacesel -= 1;
|
|
BM_ClearHFlag(&(f->head), BM_SELECT);
|
|
|
|
/*flush down to edges*/
|
|
BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
|
|
BM_ITER(f2, &fiter, bm, BM_FACES_OF_EDGE, l->e) {
|
|
if (BM_TestHFlag(f2, BM_SELECT))
|
|
break;
|
|
}
|
|
|
|
if (!f2) {
|
|
BM_Select(bm, l->e, 0);
|
|
}
|
|
}
|
|
|
|
/*flush down to verts*/
|
|
BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
|
|
BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, l->v) {
|
|
if (BM_TestHFlag(e, BM_SELECT))
|
|
break;
|
|
}
|
|
|
|
if (!e) {
|
|
BM_Select(bm, l->v, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* BMESH SELECTMODE SET
|
|
*
|
|
* Sets the selection mode for the bmesh
|
|
*
|
|
*/
|
|
|
|
void BM_Selectmode_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 = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm ); e; e= BMIter_Step(&edges))
|
|
BM_ClearHFlag(e, 0);
|
|
for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f= BMIter_Step(&faces))
|
|
BM_ClearHFlag(f, 0);
|
|
BM_SelectMode_Flush(bm);
|
|
}
|
|
else if(bm->selectmode & SCE_SELECT_EDGE) {
|
|
for(v= BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm ); v; v= BMIter_Step(&verts))
|
|
BM_ClearHFlag(v, 0);
|
|
for(e= BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm ); e; e= BMIter_Step(&edges)){
|
|
if(BM_TestHFlag(&(e->head), BM_SELECT))
|
|
BM_Select_Edge(bm, e, 1);
|
|
}
|
|
BM_SelectMode_Flush(bm);
|
|
}
|
|
else if(bm->selectmode & SCE_SELECT_FACE) {
|
|
for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm ); e; e= BMIter_Step(&edges))
|
|
BM_ClearHFlag(e, 0);
|
|
for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f= BMIter_Step(&faces)){
|
|
if(BM_TestHFlag(&(f->head), BM_SELECT))
|
|
BM_Select_Face(bm, f, 1);
|
|
}
|
|
BM_SelectMode_Flush(bm);
|
|
}
|
|
}
|
|
|
|
|
|
int BM_CountFlag(struct BMesh *bm, int type, int flag, int respecthide)
|
|
{
|
|
BMHeader *head;
|
|
BMIter iter;
|
|
int tot = 0;
|
|
|
|
if (type & BM_VERT) {
|
|
for (head = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); head; head=BMIter_Step(&iter)) {
|
|
if (respecthide && BM_TestHFlag(head, BM_HIDDEN)) continue;
|
|
if (head->flag & flag) tot++;
|
|
}
|
|
}
|
|
if (type & BM_EDGE) {
|
|
for (head = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL); head; head=BMIter_Step(&iter)) {
|
|
if (respecthide && BM_TestHFlag(head, BM_HIDDEN)) continue;
|
|
if (head->flag & flag) tot++;
|
|
}
|
|
}
|
|
if (type & BM_FACE) {
|
|
for (head = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL); head; head=BMIter_Step(&iter)) {
|
|
if (respecthide && BM_TestHFlag(head, BM_HIDDEN)) continue;
|
|
if (head->flag & flag) tot++;
|
|
}
|
|
}
|
|
|
|
return tot;
|
|
}
|
|
|
|
/*note: by design, this will not touch the editselection history stuff*/
|
|
void BM_Select(struct BMesh *bm, void *element, int select)
|
|
{
|
|
BMHeader *head = element;
|
|
|
|
if(head->type == BM_VERT) BM_Select_Vert(bm, (BMVert*)element, select);
|
|
else if(head->type == BM_EDGE) BM_Select_Edge(bm, (BMEdge*)element, select);
|
|
else if(head->type == BM_FACE) BM_Select_Face(bm, (BMFace*)element, select);
|
|
}
|
|
|
|
int BM_Selected(BMesh *bm, void *element)
|
|
{
|
|
BMHeader *head = element;
|
|
return BM_TestHFlag(head, BM_SELECT);
|
|
}
|
|
|
|
|
|
/* 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 *em, float *center, BMEditSelection *ese)
|
|
{
|
|
if (ese->type==BM_VERT) {
|
|
BMVert *eve= ese->data;
|
|
copy_v3_v3(center, eve->co);
|
|
} else if (ese->type==BM_EDGE) {
|
|
BMEdge *eed= ese->data;
|
|
add_v3_v3v3(center, eed->v1->co, eed->v2->co);
|
|
mul_v3_fl(center, 0.5);
|
|
} else if (ese->type==BM_FACE) {
|
|
BMFace *efa= ese->data;
|
|
BM_Compute_Face_Center(em, efa, center);
|
|
}
|
|
}
|
|
|
|
void BM_editselection_normal(float *normal, BMEditSelection *ese)
|
|
{
|
|
if (ese->type==BM_VERT) {
|
|
BMVert *eve= ese->data;
|
|
copy_v3_v3(normal, eve->no);
|
|
} else if (ese->type==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(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, normal, plane);
|
|
cross_v3_v3v3(normal, plane, vec);
|
|
normalize_v3(normal);
|
|
|
|
} else if (ese->type==BM_FACE) {
|
|
BMFace *efa= ese->data;
|
|
copy_v3_v3(normal, efa->no);
|
|
}
|
|
}
|
|
|
|
/* Calculate a plane that is rightangles to the edge/vert/faces normal
|
|
also make the plane run allong an axis that is related to the geometry,
|
|
because this is used for the manipulators Y axis.*/
|
|
void BM_editselection_plane(BMesh *em, float *plane, BMEditSelection *ese)
|
|
{
|
|
if (ese->type==BM_VERT) {
|
|
BMVert *eve= ese->data;
|
|
float vec[3]={0,0,0};
|
|
|
|
if (ese->prev) { /*use previously selected data to make a usefull vertex plane */
|
|
BM_editselection_center(em, vec, ese->prev);
|
|
sub_v3_v3v3(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.5) vec[0]=1;
|
|
else if (eve->no[1]<0.5) vec[1]=1;
|
|
else vec[2]=1;
|
|
cross_v3_v3v3(plane, eve->no, vec);
|
|
}
|
|
} else if (ese->type==BM_EDGE) {
|
|
BMEdge *eed= ese->data;
|
|
|
|
/*the plane is simple, it runs allong 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(plane, eed->v2->co, eed->v1->co);
|
|
else
|
|
sub_v3_v3v3(plane, eed->v1->co, eed->v2->co);
|
|
|
|
} else if (ese->type==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->no[0]<0.5) vec[0]=1.0f;
|
|
else if (efa->no[1]<0.5) vec[1]=1.0f;
|
|
else vec[2]=1.0f;
|
|
cross_v3_v3v3(plane, efa->no, vec);
|
|
#if 0 //BMESH_TODO
|
|
|
|
if (efa->v4) { /*if its a quad- set the plane along the 2 longest edges.*/
|
|
float vecA[3], vecB[3];
|
|
sub_v3_v3v3(vecA, efa->v4->co, efa->v3->co);
|
|
sub_v3_v3v3(vecB, efa->v1->co, efa->v2->co);
|
|
add_v3_v3v3(plane, vecA, vecB);
|
|
|
|
sub_v3_v3v3(vecA, efa->v1->co, efa->v4->co);
|
|
sub_v3_v3v3(vecB, efa->v2->co, efa->v3->co);
|
|
add_v3_v3v3(vec, vecA, vecB);
|
|
/*use the biggest edge length*/
|
|
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])
|
|
copy_v3_v3(plane, vec);
|
|
} else {
|
|
/*start with v1-2 */
|
|
sub_v3_v3v3(plane, efa->v1->co, efa->v2->co);
|
|
|
|
/*test the edge between v2-3, use if longer */
|
|
sub_v3_v3v3(vec, efa->v2->co, efa->v3->co);
|
|
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])
|
|
copy_v3_v3(plane, vec);
|
|
|
|
/*test the edge between v1-3, use if longer */
|
|
sub_v3_v3v3(vec, efa->v3->co, efa->v1->co);
|
|
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])
|
|
copy_v3_v3(plane, vec);
|
|
}
|
|
#endif
|
|
}
|
|
normalize_v3(plane);
|
|
}
|
|
|
|
static int BM_check_selection(BMesh *em, void *data)
|
|
{
|
|
BMEditSelection *ese;
|
|
|
|
for(ese = em->selected.first; ese; ese = ese->next){
|
|
if(ese->data == data) return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void BM_remove_selection(BMesh *em, void *data)
|
|
{
|
|
BMEditSelection *ese;
|
|
for(ese=em->selected.first; ese; ese = ese->next){
|
|
if(ese->data == data){
|
|
BLI_freelinkN(&(em->selected),ese);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void BM_clear_selection_history(BMesh *em)
|
|
{
|
|
BLI_freelistN(&em->selected);
|
|
em->selected.first = em->selected.last = NULL;
|
|
}
|
|
|
|
void BM_store_selection(BMesh *em, void *data)
|
|
{
|
|
BMEditSelection *ese;
|
|
if(!BM_check_selection(em, data)){
|
|
ese = (BMEditSelection*) MEM_callocN( sizeof(BMEditSelection), "BMEdit Selection");
|
|
ese->type = ((BMHeader*)data)->type;
|
|
ese->data = data;
|
|
BLI_addtail(&(em->selected),ese);
|
|
}
|
|
}
|
|
|
|
void BM_validate_selections(BMesh *em)
|
|
{
|
|
BMEditSelection *ese, *nextese;
|
|
|
|
ese = em->selected.first;
|
|
|
|
while(ese){
|
|
nextese = ese->next;
|
|
if (!BM_TestHFlag(ese->data, BM_SELECT)) BLI_freelinkN(&(em->selected), ese);
|
|
ese = nextese;
|
|
}
|
|
}
|
|
|
|
void BM_clear_flag_all(BMesh *bm, int flag)
|
|
{
|
|
BMIter iter;
|
|
BMHeader *ele;
|
|
int i, type;
|
|
|
|
if (flag & BM_SELECT)
|
|
BM_clear_selection_history(bm);
|
|
|
|
for (i=0; i<3; i++) {
|
|
switch (i) {
|
|
case 0:
|
|
type = BM_VERTS_OF_MESH;
|
|
break;
|
|
case 1:
|
|
type = BM_EDGES_OF_MESH;
|
|
break;
|
|
case 2:
|
|
type = BM_FACES_OF_MESH;
|
|
break;
|
|
}
|
|
|
|
ele = BMIter_New(&iter, bm, type, NULL);
|
|
for ( ; ele; ele=BMIter_Step(&iter)) {
|
|
if (flag & BM_SELECT) BM_Select(bm, ele, 0);
|
|
BM_ClearHFlag(ele, flag);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***************** Pinning **************/
|
|
|
|
#define SETPIN(ele) pin ? BM_SetHFlag(ele, BM_PINNED) : BM_ClearHFlag(ele, BM_PINNED);
|
|
|
|
|
|
void BM_Pin_Vert(BMesh *bm, BMVert *v, int pin)
|
|
{
|
|
SETPIN(v);
|
|
}
|
|
|
|
void BM_Pin_Edge(BMesh *bm, BMEdge *e, int pin)
|
|
{
|
|
SETPIN(e->v1);
|
|
SETPIN(e->v2);
|
|
}
|
|
|
|
void BM_Pin_Face(BMesh *bm, BMFace *f, int pin)
|
|
{
|
|
BMIter vfiter;
|
|
BMVert *vf;
|
|
|
|
BM_ITER(vf, &vfiter, bm, BM_VERTS_OF_FACE, f) {
|
|
SETPIN(vf);
|
|
}
|
|
}
|
|
|
|
void BM_Pin(BMesh *bm, void *element, int pin)
|
|
{
|
|
BMHeader *h = element;
|
|
|
|
switch (h->type) {
|
|
case BM_VERT:
|
|
BM_Pin_Vert(bm, element, pin);
|
|
break;
|
|
case BM_EDGE:
|
|
BM_Pin_Edge(bm, element, pin);
|
|
break;
|
|
case BM_FACE:
|
|
BM_Pin_Face(bm, element, pin);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/***************** Mesh Hiding stuff *************/
|
|
|
|
#define SETHIDE(ele) hide ? BM_SetHFlag(ele, BM_HIDDEN) : BM_ClearHFlag(ele, BM_HIDDEN);
|
|
|
|
static void vert_flush_hide(BMesh *bm, BMVert *v) {
|
|
BMIter iter;
|
|
BMEdge *e;
|
|
|
|
BM_ITER(e, &iter, bm, BM_EDGES_OF_VERT, v) {
|
|
if (!BM_TestHFlag(e, BM_HIDDEN))
|
|
return;
|
|
}
|
|
|
|
BM_SetHFlag(v, BM_HIDDEN);
|
|
}
|
|
|
|
static void edge_flush_hide(BMesh *bm, BMEdge *e) {
|
|
BMIter iter;
|
|
BMFace *f;
|
|
|
|
BM_ITER(f, &iter, bm, BM_FACES_OF_EDGE, e) {
|
|
if (!BM_TestHFlag(f, BM_HIDDEN))
|
|
return;
|
|
}
|
|
|
|
BM_SetHFlag(e, BM_HIDDEN);
|
|
}
|
|
|
|
void BM_Hide_Vert(BMesh *bm, BMVert *v, int hide)
|
|
{
|
|
/*vert hiding: vert + surrounding edges and faces*/
|
|
BMIter iter, fiter;
|
|
BMEdge *e;
|
|
BMFace *f;
|
|
|
|
SETHIDE(v);
|
|
|
|
BM_ITER(e, &iter, bm, BM_EDGES_OF_VERT, v) {
|
|
SETHIDE(e);
|
|
|
|
BM_ITER(f, &fiter, bm, BM_FACES_OF_EDGE, e) {
|
|
SETHIDE(f);
|
|
}
|
|
}
|
|
}
|
|
|
|
void BM_Hide_Edge(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) {
|
|
SETHIDE(f);
|
|
}
|
|
|
|
SETHIDE(e);
|
|
|
|
/*hide vertices if necassary*/
|
|
vert_flush_hide(bm, e->v1);
|
|
vert_flush_hide(bm, e->v2);
|
|
}
|
|
|
|
void BM_Hide_Face(BMesh *bm, BMFace *f, int hide)
|
|
{
|
|
BMIter iter;
|
|
BMLoop *l;
|
|
|
|
/**/
|
|
SETHIDE(f);
|
|
|
|
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(bm, l->v);
|
|
}
|
|
}
|
|
|
|
void BM_Hide(BMesh *bm, void *element, int hide)
|
|
{
|
|
BMHeader *h = element;
|
|
|
|
switch (h->type) {
|
|
case BM_VERT:
|
|
BM_Hide_Vert(bm, element, hide);
|
|
break;
|
|
case BM_EDGE:
|
|
BM_Hide_Edge(bm, element, hide);
|
|
break;
|
|
case BM_FACE:
|
|
BM_Hide_Face(bm, element, hide);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|