From 5018318fe0619565707e50cb66b836bd25997912 Mon Sep 17 00:00:00 2001 From: Joseph Eagar Date: Mon, 9 Mar 2009 09:52:32 +0000 Subject: [PATCH] dissolve faces: errors-out on holes, preserves winding, and doesn't delete original face if no dissolving happened. the conversion from/to editmesh now counts selected elements properly. --- source/blender/bmesh/bmesh.h | 1 + source/blender/bmesh/bmesh_operators.h | 5 +- source/blender/bmesh/intern/bmesh_construct.c | 25 ++++-- source/blender/bmesh/intern/bmesh_opdefines.c | 2 +- source/blender/bmesh/intern/bmesh_queries.c | 2 +- .../blender/bmesh/intern/bmesh_to_editmesh.c | 6 +- .../blender/bmesh/intern/editmesh_to_bmesh.c | 10 ++- source/blender/bmesh/operators/dissolveops.c | 83 +++++++++++-------- source/blender/editors/mesh/editmesh_add.c | 37 +++++++-- 9 files changed, 118 insertions(+), 53 deletions(-) diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h index 054e8156665..7f532843dc9 100644 --- a/source/blender/bmesh/bmesh.h +++ b/source/blender/bmesh/bmesh.h @@ -76,6 +76,7 @@ struct BMLoop; #define BM_HIDDEN (1<<3) #define BM_SHARP (1<<4) #define BM_SMOOTH (1<<5) +#define BM_ACTIVE (1<<6) typedef struct BMHeader { struct BMHeader *next, *prev; diff --git a/source/blender/bmesh/bmesh_operators.h b/source/blender/bmesh/bmesh_operators.h index 37225ab342e..9b368b2acfd 100644 --- a/source/blender/bmesh/bmesh_operators.h +++ b/source/blender/bmesh/bmesh_operators.h @@ -86,6 +86,8 @@ void BMO_Set_Pnt(struct BMOperator *op, int slotcode, void *p); void BMO_Set_Vec(struct BMOperator *op, int slotcode, float *vec); void BMO_SetFlag(struct BMesh *bm, void *element, int flag); void BMO_ClearFlag(struct BMesh *bm, void *element, int flag); + +/*flags 15 and 16 (1<<14 and 1<<15) are reserved for bmesh api use*/ int BMO_TestFlag(struct BMesh *bm, void *element, int flag); int BMO_CountFlag(struct BMesh *bm, int flag, int type); void BMO_Flag_To_Slot(struct BMesh *bm, struct BMOperator *op, int slotcode, int flag, int type); @@ -340,10 +342,9 @@ void BM_esubdivideflag(struct Object *obedit, struct BMesh *bm, int selflag, flo int flag, int numcuts, int seltype); void BM_extrudefaceflag(BMesh *bm, int flag); -/*these next two return 1 if they did anything, or zero otherwise. +/*this next one return 1 if they did anything, or zero otherwise. they're kindof a hackish way to integrate with fkey, until such time as fkey is completely bmeshafied.*/ -int BM_DissolveFaces(struct EditMesh *em, int flag); /*this doesn't display errors to the user, btw*/ int BM_ConnectVerts(struct EditMesh *em, int flag); diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index d302a85ec72..f061358c8f8 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -210,20 +210,33 @@ void BM_Face_CopyShared(BMesh *bm, BMFace *f) { BMFace *BM_Make_Ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, int len, int nodouble) { BMVert *vert_buf[VERT_BUF_SIZE]; - BMVert **verts = vert_buf; + BMVert **verts = vert_buf, *lastv; BMFace *f = NULL; - int overlap = 0, i; + int overlap = 0, i, j; if(nodouble){ if(len > VERT_BUF_SIZE) verts = MEM_callocN(sizeof(BMVert *) * len, "bmesh make ngon vertex array"); - for(i = 0; i < len; i++){ + + /*if ((edges[i]->v1 == edges[i]->v1) || + (edges[i]->v1 == edges[i]->v2)) + { + lastv = edges[i]->v2; + } else lastv = edges[i]->v1; + verts[0] = lastv; + + for (i=1; iv1, BM_EDGEVERT)){ BMO_SetFlag(bm, edges[i]->v1, BM_EDGEVERT); - verts[i] = edges[i]->v1; - } else if(!BMO_TestFlag(bm, edges[i]->v2, BM_EDGEVERT)) { + verts[j++] = edges[i]->v1; + } + if(!BMO_TestFlag(bm, edges[i]->v2, BM_EDGEVERT)) { BMO_SetFlag(bm, edges[i]->v2, BM_EDGEVERT); - verts[i] = edges[i]->v2; + verts[j++] = edges[i]->v2; } } diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index 28cf5d881c8..4fd8239ca05 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -4,7 +4,7 @@ #include BMOpDefine def_connectverts = { - "connectvert", + "connectverts", {{BMOP_OPSLOT_PNT_BUF, "verts"}, {BMOP_OPSLOT_PNT_BUF, "edgeout"}}, connectverts_exec, diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index a38f3992dfe..9bc4fe03fdc 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -114,7 +114,7 @@ int BM_Verts_In_Face(BMesh *bm, BMFace *f, BMVert **varr, int len) curloop = f->loopbase; do{ if(BMO_TestFlag(bm, curloop->v, BM_OVERLAP)) count++; - curloop = ((BMLoop*)(curloop->head.next)); + curloop = (BMLoop*)(curloop->head.next); } while(curloop != f->loopbase); for(i=0; i < len; i++) BMO_ClearFlag(bm, varr[i], BM_OVERLAP); diff --git a/source/blender/bmesh/intern/bmesh_to_editmesh.c b/source/blender/bmesh/intern/bmesh_to_editmesh.c index 99de531e7cd..12bf0bf5e86 100644 --- a/source/blender/bmesh/intern/bmesh_to_editmesh.c +++ b/source/blender/bmesh/intern/bmesh_to_editmesh.c @@ -167,7 +167,6 @@ static EditFace *bmeshface_to_editface(BMesh *bm, EditMesh *em, BMFace *f, EditV efa->mat_nr = (unsigned char)f->mat_nr; - /*Copy normal*/ efa->n[0] = f->no[0]; efa->n[1] = f->no[1]; @@ -177,6 +176,7 @@ static EditFace *bmeshface_to_editface(BMesh *bm, EditMesh *em, BMFace *f, EditV if (f->head.flag & BM_SELECT) efa->f |= SELECT; if (f->head.flag & BM_HIDDEN) efa->h = 1; if (f->head.flag & BM_SMOOTH) efa->flag |= ME_SMOOTH; + if (f->head.flag & BM_ACTIVE) EM_set_actFace(em, efa); CustomData_em_copy_data(&bm->pdata, &em->fdata, f->data, &efa->data); loops_to_editmesh_corners(bm, &em->fdata, efa->data, f, numCol,numTex); @@ -231,6 +231,10 @@ EditMesh *bmesh_to_editmesh_intern(BMesh *bm) EM_fgon_flags(em); + EM_nvertices_selected(em); + EM_nedges_selected(em); + EM_nfaces_selected(em); + return em; } diff --git a/source/blender/bmesh/intern/editmesh_to_bmesh.c b/source/blender/bmesh/intern/editmesh_to_bmesh.c index dfe97297161..b8431f06ff4 100644 --- a/source/blender/bmesh/intern/editmesh_to_bmesh.c +++ b/source/blender/bmesh/intern/editmesh_to_bmesh.c @@ -189,6 +189,8 @@ static BMFace *editface_to_BMFace(BMesh *bm, EditMesh *em, EditFace *efa, int nu f->mat_nr = efa->mat_nr; if(efa->f & SELECT) BM_Select_Face(bm, f, 1); if(efa->h) f->head.flag |= BM_HIDDEN; + + if (efa == em->act_face) f->head.flag |= BM_ACTIVE; CustomData_bmesh_copy_data(&em->fdata, &bm->pdata, efa->data, &f->data); editmesh_corners_to_loops(bm, &em->fdata, efa->data, f,numCol,numTex); @@ -234,7 +236,7 @@ static void fuse_fgon(BMesh *bm, BMFace *f) { BMFace *sf; BMLoop *l; - int done; + int done, act=0; sf = f; done = 0; @@ -242,8 +244,12 @@ static void fuse_fgon(BMesh *bm, BMFace *f) done = 1; l = sf->loopbase; do{ - if(l->e->head.flag & BM_FGON){ + if(l->e->head.flag & BM_FGON) { + if (l->f->head.flag & BM_ACTIVE) act = BM_ACTIVE; + if (((BMLoop*)l->radial.next->data)->f->head.flag & BM_ACTIVE) act = BM_ACTIVE; + sf = BM_Join_Faces(bm,l->f, ((BMLoop*)l->radial.next->data)->f, l->e, 0,0); + sf->head.flag |= act; if(sf){ done = 0; break; diff --git a/source/blender/bmesh/operators/dissolveops.c b/source/blender/bmesh/operators/dissolveops.c index 295fd29afc6..de6aea7bd25 100644 --- a/source/blender/bmesh/operators/dissolveops.c +++ b/source/blender/bmesh/operators/dissolveops.c @@ -13,8 +13,38 @@ #define FACE_MARK 1 #define FACE_ORIG 2 -#define VERT_MARK 1 #define FACE_NEW 4 +#define EDGE_MARK 1 + +#define VERT_MARK 1 + +static int check_hole_in_region(BMesh *bm, BMFace *f) { + BMWalker regwalker; + BMIter liter2; + BMLoop *l2, *l3; + BMFace *f2; + + /*checks if there are any unmarked boundary edges in the face region*/ + + BMW_Init(®walker, bm, BMW_ISLAND, FACE_MARK); + f2 = BMW_Begin(®walker, f); + for (; f2; f2=BMW_Step(®walker)) { + l2 = BMIter_New(&liter2, bm, BM_LOOPS_OF_FACE, f2); + for (; l2; l2=BMIter_Step(&liter2)) { + l3 = bmesh_radial_nextloop(l2); + if (BMO_TestFlag(bm, l3->f, FACE_MARK) + != BMO_TestFlag(bm, l2->f, FACE_MARK)) + { + if (!BMO_TestFlag(bm, l2->e, EDGE_MARK)) { + return 0; + } + } + } + } + BMW_End(®walker); + + return 1; +} void dissolvefaces_exec(BMesh *bm, BMOperator *op) { @@ -51,6 +81,7 @@ void dissolvefaces_exec(BMesh *bm, BMOperator *op) for (; l; l=BMW_Step(&walker)) { V_GROW(region); region[V_COUNT(region)-1] = l; + BMO_SetFlag(bm, l->e, EDGE_MARK); } BMW_End(&walker); @@ -62,6 +93,14 @@ void dissolvefaces_exec(BMesh *bm, BMOperator *op) if (region == NULL) continue; + /*check for holes in boundary*/ + if (!check_hole_in_region(bm, region[0]->f)) { + BMO_RaiseError(bm, op, + BMERR_DISSOLVEFACES_FAILED, + "Hole(s) in face region"); + goto cleanup; + } + BMW_Init(®walker, bm, BMW_ISLAND, FACE_MARK); f2 = BMW_Begin(®walker, region[0]->f); for (; f2; f2=BMW_Step(®walker)) { @@ -95,22 +134,11 @@ void dissolvefaces_exec(BMesh *bm, BMOperator *op) edges[V_COUNT(edges)-1] = region[j]->e; } - f= BM_Make_Ngon(bm, edges[0]->v1, edges[0]->v2, edges, j, 0); - - if (!f) continue; - - /* - NOTE: sadly, make ngon's overlap checking option - crashes ;/ - make ngon can fail, if there was already an existing face. - this is desired behaviour, I think, so we'll just silently - ignore any possible other error cases. - if (!f) { - //raise error - BMO_RaiseError(bm, op, BMERR_DISSOLVEFACES_FAILED, NULL); - goto cleanup; - }*/ + f= BM_Make_Ngon(bm, region[0]->v, region[1]->v, edges, j, 1); + /*if making the new face failed (e.g. overlapping test) + unmark the original faces for deletion.*/ + BMO_ClearFlag(bm, f, FACE_ORIG); BMO_SetFlag(bm, f, FACE_NEW); fcopied = 0; @@ -155,24 +183,6 @@ cleanup: V_FREE(regions); } -/*returns 1 if any faces were dissolved*/ -int BM_DissolveFaces(EditMesh *em, int flag) { - BMesh *bm = editmesh_to_bmesh(em); - EditMesh *em2; - BMOperator op; - - BMO_Init_Op(&op, BMOP_DISSOLVE_FACES); - BMO_HeaderFlag_To_Slot(bm, &op, BMOP_DISFACES_FACEIN, flag, BM_FACE); - BMO_Exec_Op(bm, &op); - BMO_Finish_Op(bm, &op); - - em2 = bmesh_to_editmesh(bm); - set_editMesh(em, em2); - MEM_freeN(em2); - - return BMO_GetSlot(&op, BMOP_DISFACES_REGIONOUT)->len > 0; -} - void dissolveverts_exec(BMesh *bm, BMOperator *op) { BMOpSlot *vinput; @@ -195,8 +205,11 @@ void dissolveverts_exec(BMesh *bm, BMOperator *op) BMO_CallOpf(bm, "dissolvefaces faces=%ff", FACE_MARK); if (BMO_HasError(bm)) { + char *msg; + + BMO_GetError(bm, &msg, NULL); BMO_ClearStack(bm); - BMO_RaiseError(bm, op, BMERR_DISSOLVEVERTS_FAILED, NULL); + BMO_RaiseError(bm, op, BMERR_DISSOLVEVERTS_FAILED,msg); } } diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c index 8651abac0a9..b32c733ad8c 100644 --- a/source/blender/editors/mesh/editmesh_add.c +++ b/source/blender/editors/mesh/editmesh_add.c @@ -669,15 +669,42 @@ static void addedgeface_mesh(EditMesh *em, wmOperator *op) EditFace *efa; short amount=0; + /*return if bmesh vert connect does anything.*/ if (em->selectmode & SCE_SELECT_VERTEX) { - /*return if bmesh vert connect does anything.*/ - if (BM_ConnectVerts(em, BM_SELECT)) return; + BMesh *bm = editmesh_to_bmesh(em); + BMOperator bmop; + int len, ok; + + BMO_InitOpf(bm, &bmop, "connectverts verts=%hv", BM_SELECT); + BMO_Exec_Op(bm, &bmop); + BMO_Finish_Op(bm, &bmop); + + ok = EDBM_Finish(bm, em, op, 1); + if (!ok) return OPERATOR_CANCELLED; + + len = BMO_GetSlot(&bmop, BM_CONVERTS_EDGEOUT)->len; + if (len) return; } + /*return if bmesh face dissolve finds stuff to + dissolve. this entire tool should be + bmeshafied eventually, but until then + hacks like this to integrate with it + are necassary.*/ if (em->selectmode & SCE_SELECT_FACE) { - /*return if bmesh face dissolve finds stuff to - dissolve.*/ - if (BM_DissolveFaces(em, BM_SELECT)) return; + BMesh *bm = editmesh_to_bmesh(em); + BMOperator bmop; + int len, ok; + + BMO_InitOpf(bm, &bmop, "dissolvefaces faces=%hf", BM_SELECT); + BMO_Exec_Op(bm, &bmop); + BMO_Finish_Op(bm, &bmop); + + ok = EDBM_Finish(bm, em, op, 1); + if (!ok) return OPERATOR_CANCELLED; + + len = BMO_GetSlot(&bmop, BMOP_DISFACES_REGIONOUT)->len; + if (len) return; } /* how many selected ? */ -- 2.28.0