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.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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; i<len; i++) {
|
||||
if (!BMO_TestFlag
|
||||
}*/
|
||||
|
||||
for(i = 0, j=0; i < len; i++){
|
||||
if(!BMO_TestFlag(bm, edges[i]->v1, 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
BMOpDefine def_connectverts = {
|
||||
"connectvert",
|
||||
"connectverts",
|
||||
{{BMOP_OPSLOT_PNT_BUF, "verts"},
|
||||
{BMOP_OPSLOT_PNT_BUF, "edgeout"}},
|
||||
connectverts_exec,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 ? */
|
||||
|
||||
Reference in New Issue
Block a user