Shift-G (select similar) is now bmeshafied for face select mode.

The patch was by Wael El Oraiby, who did a great job on it.
Yay for Wael!  Commit of patch #19242.

There's also some CCGSubSurf stuff mixed in with this, though it's
still not working right (fixed tons of bugs, just the main ones
for some reason are still there, despite their original causes
being fixed :-/).
This commit is contained in:
Joseph Eagar
2009-08-22 04:45:19 +00:00
parent 1aeb5a6925
commit 8151a51684
9 changed files with 371 additions and 195 deletions

View File

@@ -285,7 +285,7 @@ void dm_add_polys_from_iter(CustomData *ldata, CustomData *pdata, DerivedMesh *d
CustomData *oldata, *opdata;
MPoly *mpoly;
MLoop *mloop;
int l, i, j, lasttype;
int p, l, i, j, lasttype;
oldata = dm->getLoopDataLayout(dm);
opdata = dm->getFaceDataLayout(dm);
@@ -299,7 +299,7 @@ void dm_add_polys_from_iter(CustomData *ldata, CustomData *pdata, DerivedMesh *d
CustomData_add_layer(pdata, CD_MPOLY, CD_ASSIGN, mpoly, dm->getNumFaces(dm));
l = 0;
for (; !iter->done; iter->step(iter), mpoly++) {
for (p=0; !iter->done; iter->step(iter), mpoly++, p++) {
mpoly->flag = iter->flags;
mpoly->loopstart = l;
mpoly->totloop = iter->len;
@@ -314,7 +314,10 @@ void dm_add_polys_from_iter(CustomData *ldata, CustomData *pdata, DerivedMesh *d
continue;
e1 = iter->getCDData(iter, opdata->layers[i].type, j);
e2 = CustomData_get_layer_n(pdata, opdata->layers[i].type, j);
e2 = (char*)CustomData_get_n(pdata, opdata->layers[i].type, p, j);
if (!e2)
continue;
CustomData_copy_elements(opdata->layers[i].type, e1, e2, 1);
@@ -340,7 +343,10 @@ void dm_add_polys_from_iter(CustomData *ldata, CustomData *pdata, DerivedMesh *d
continue;
e1 = liter->getLoopCDData(liter, oldata->layers[i].type, j);
e2 = CustomData_get_layer_n(ldata, oldata->layers[i].type, j);
e2 = CustomData_get_n(ldata, oldata->layers[i].type, l, j);
if (!e2)
continue;
CustomData_copy_elements(oldata->layers[i].type, e1, e2, 1);

View File

@@ -1644,7 +1644,7 @@ void *CustomData_get_n(const CustomData *data, int type, int index, int n)
if(layer_index < 0) return NULL;
offset = layerType_getInfo(type)->size * index;
return (char *)data->layers[layer_index].data + offset;
return (char *)data->layers[layer_index+n].data + offset;
}
void *CustomData_get_layer(const CustomData *data, int type)

View File

@@ -193,6 +193,9 @@ BMEditMesh *CDDM_To_BMesh(DerivedMesh *dm, BMEditMesh *existing)
verts[j] = vtable[dliter->vindex];
edges[j] = etable[dliter->eindex];
}
if (j < 2)
break;
f = BM_Make_Ngon(bm, verts[0], verts[1], edges, dfiter->len, 0);
f->head.flag = MEFlags_To_BMFlags(dfiter->flags, BM_FACE);

View File

@@ -1460,6 +1460,7 @@ struct cgdm_faceIter;
typedef struct cgdm_loopIter {
DMLoopIter head;
int curloop;
int lindex; //loop index within the mesh, not the face
CCGDerivedMesh *cgdm;
struct cgdm_faceIter *fiter;
} cgdm_loopIter;
@@ -1493,7 +1494,7 @@ void cgdm_faceIterStep(void *self)
fiter->head.flags = fiter->mface.flag;
fiter->head.mat_nr = fiter->mface.mat_nr;
fiter->head.len = fiter->mface.v4 ? 4 : 3;
fiter->head.len = 4;
}
void *cgdm_faceIterCData(void *self, int type, int layer)
@@ -1501,9 +1502,9 @@ void *cgdm_faceIterCData(void *self, int type, int layer)
cgdm_faceIter *fiter = self;
if (layer == -1)
return CustomData_get(&fiter->cgdm->dm.faceData, fiter->head.index, type);
return CustomData_get(&fiter->cgdm->dm.polyData, fiter->head.index, type);
else
return CustomData_get_n(&fiter->cgdm->dm.faceData, type, fiter->head.index, layer);
return CustomData_get_n(&fiter->cgdm->dm.polyData, type, fiter->head.index, layer);
}
void cgdm_loopIterStep(void *self)
@@ -1512,14 +1513,14 @@ void cgdm_loopIterStep(void *self)
MFace *mf = &liter->fiter->mface;
int i, v1, v2;
if (liter->head.index >= liter->fiter->head.len) {
liter->head.index++;
i = liter->head.index;
if (liter->head.index >= 4) {
liter->head.done = 1;
return;
}
liter->head.index++;
i = liter->head.index;
switch (i) {
case 0:
v1 = liter->fiter->mface.v1;
@@ -1541,6 +1542,7 @@ void cgdm_loopIterStep(void *self)
liter->head.vindex = v1;
liter->head.eindex = GET_INT_FROM_POINTER(BLI_edgehash_lookup(liter->fiter->ehash, v1, v2));
liter->lindex += 1;
cgdm_getFinalVert((DerivedMesh*)liter->cgdm, v1, &liter->head.v);
}
@@ -1557,10 +1559,10 @@ void *cgdm_loopIterGetVCData(void *self, int type, int layer)
void *cgdm_loopIterGetCData(void *self, int type, int layer)
{
cgdm_loopIter *liter = self;
/*BMESH_TODO
yeek, this has to convert mface-style uv/mcols to loop-style*/
return NULL;
if (layer == -1)
return CustomData_get(&liter->cgdm->dm.loopData, liter->lindex, type);
else return CustomData_get_n(&liter->cgdm->dm.loopData, type, liter->lindex, layer);
}
DMLoopIter *cgdm_faceIterGetLIter(void *self)
@@ -1587,6 +1589,8 @@ DMFaceIter *cgdm_newFaceIter(DerivedMesh *dm)
MEdge medge;
int i, totedge = cgdm_getNumEdges(dm);
fiter->cgdm = dm;
fiter->liter.cgdm = dm;
fiter->ehash = BLI_edgehash_new();
for (i=0; i<totedge; i++) {
@@ -1604,6 +1608,7 @@ DMFaceIter *cgdm_newFaceIter(DerivedMesh *dm)
fiter->liter.head.getLoopCDData = cgdm_loopIterGetCData;
fiter->liter.head.getVertCDData = cgdm_loopIterGetVCData;
fiter->liter.head.step = cgdm_loopIterStep;
fiter->liter.lindex = -1;
fiter->head.step(fiter);
}
@@ -2627,7 +2632,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CSubSurf *ss,
int numTex, numCol;
int gridInternalEdges;
int index2;
float *w = NULL;
float *w = NULL, one = 1.0f;
WeightTable wtable = {0};
V_DECLARE(w);
/* MVert *mvert = NULL; - as yet unused */
@@ -2864,12 +2869,13 @@ static CCGDerivedMesh *getCCGDerivedMesh(CSubSurf *ss,
loopindex2++;
/*copy over poly data, e.g. mtexpoly*/
CustomData_interp(&dm->polyData, &cgdm->dm.polyData, &origIndex, w, NULL, 1, index2);
CustomData_interp(&dm->polyData, &cgdm->dm.polyData, &origIndex, &one, NULL, 1, index2);
/*generate tesselated face data used for drawing*/
ccg_loops_to_corners(&cgdm->dm.faceData, &cgdm->dm.loopData,
&cgdm->dm.polyData, loopindex2-4, index2, index2, numTex, numCol);
faceNum++;
index2++;
}
}
@@ -2878,25 +2884,6 @@ static CCGDerivedMesh *getCCGDerivedMesh(CSubSurf *ss,
edgeNum += numFinalEdges;
}
for(index = 0; index < totvert; ++index) {
CCVert *v = cgdm->vertMap[index].vert;
int mapIndex = cgdm_getVertMapIndex(cgdm->ss, v);
int vidx;
vidx = GET_INT_FROM_POINTER(CCS_getVertVertHandle(v));
cgdm->vertMap[index].startVert = vertNum;
/* set the vert base vert */
*((int*) CCS_getVertUserData(ss, v)) = vertNum;
DM_copy_vert_data(dm, &cgdm->dm, vidx, vertNum, 1);
*vertOrigIndex = mapIndex;
++vertOrigIndex;
++vertNum;
}
edgeFlags = DM_get_edge_data_layer(&cgdm->dm, CD_FLAGS);
for(index = 0; index < totedge; ++index) {
CCEdge *e = cgdm->edgeMap[index].edge;
@@ -2938,6 +2925,25 @@ static CCGDerivedMesh *getCCGDerivedMesh(CSubSurf *ss,
edgeNum += numFinalEdges;
}
for(index = 0; index < totvert; ++index) {
CCVert *v = cgdm->vertMap[index].vert;
int mapIndex = cgdm_getVertMapIndex(cgdm->ss, v);
int vidx;
vidx = GET_INT_FROM_POINTER(CCS_getVertVertHandle(v));
cgdm->vertMap[index].startVert = vertNum;
/* set the vert base vert */
*((int*) CCS_getVertUserData(ss, v)) = vertNum;
DM_copy_vert_data(dm, &cgdm->dm, vidx, vertNum, 1);
*vertOrigIndex = mapIndex;
++vertOrigIndex;
++vertNum;
}
#if 0
for(index = 0; index < totface; ++index) {
CCFace *f = cgdm->faceMap[index].face;

View File

@@ -22,6 +22,15 @@ enum {
SUBD_STRAIGHT_CUT,
};
enum {
SIMFACE_MATERIAL = 201,
SIMFACE_IMAGE,
SIMFACE_AREA,
SIMFACE_PERIMETER,
SIMFACE_NORMAL,
SIMFACE_COPLANAR,
};
extern BMOpDefine *opdefines[];
extern int bmesh_total_ops;

View File

@@ -613,6 +613,22 @@ BMOpDefine def_splitop = {
0
};
/*
Similar faces select
Select similar faces (area/material/perimeter....).
*/
BMOpDefine def_similarfaces = {
"similarfaces",
{{BMOP_OPSLOT_ELEMENT_BUF, "faces"}, /* input faces */
{BMOP_OPSLOT_ELEMENT_BUF, "faceout"}, /* output faces */
{BMOP_OPSLOT_INT, "type"}, /* type of selection */
{BMOP_OPSLOT_FLT, "thresh"}, /* threshold of selection */
{0} /*null-terminating sentinel*/},
bmesh_similarfaces_exec,
0
};
BMOpDefine *opdefines[] = {
&def_splitop,
&def_dupeop,
@@ -653,6 +669,7 @@ BMOpDefine *opdefines[] = {
&def_collapse_uvs,
&def_pointmerge,
&def_collapse,
&def_similarfaces,
};
int bmesh_total_ops = (sizeof(opdefines) / sizeof(void*));

View File

@@ -46,5 +46,6 @@ void bmesh_extrude_face_indiv_exec(BMesh *bm, BMOperator *op);
void bmesh_collapsecon_exec(BMesh *bm, BMOperator *op);
void bmesh_pointmerge_exec(BMesh *bm, BMOperator *op);
void bmesh_collapse_exec(BMesh *bm, BMOperator *op);
void bmesh_similarfaces_exec(BMesh *bm, BMOperator *op);
#endif

View File

@@ -383,3 +383,264 @@ void bmesh_vertexsmooth_exec(BMesh *bm, BMOperator *op)
V_FREE(cos);
}
/*
** compute the centroid of an ngon
**
** NOTE: This should probably go to bmesh_polygon.c and replace the function that compute its center
** basing on bounding box
*/
static void ngon_center(float *v, BMesh *bm, BMFace *f)
{
BMIter liter;
BMLoop *l;
v[0] = v[1] = v[2] = 0;
BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
VecAddf(v, v, l->v->co);
}
if( f->len )
{
v[0] /= f->len;
v[1] /= f->len;
v[2] /= f->len;
}
}
/*
** compute the perimeter of an ngon
**
** NOTE: This should probably go to bmesh_polygon.c
*/
static float ngon_perimeter(BMesh *bm, BMFace *f)
{
BMIter liter;
BMLoop *l;
int num_verts = 0;
float v[3], sv[3];
float perimeter = 0.0f;
BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
if( num_verts == 0 ) {
sv[0] = v[0] = l->v->co[0];
sv[1] = v[1] = l->v->co[1];
sv[2] = v[2] = l->v->co[2];
num_verts++;
} else {
perimeter += VecLenf(v, l->v->co);
v[0] = l->v->co[0];
v[1] = l->v->co[1];
v[2] = l->v->co[2];
num_verts++;
}
}
perimeter += VecLenf(v, sv);
return perimeter;
}
/*
** compute the fake surface of an ngon
** This is done by decomposing the ngon into triangles who share the centroid of the ngon
** while this method is far from being exact, it should garantee an invariance.
**
** NOTE: This should probably go to bmesh_polygon.c
*/
static float ngon_fake_area(BMesh *bm, BMFace *f)
{
BMIter liter;
BMLoop *l;
int num_verts = 0;
float v[3], sv[3], c[3];
float area = 0.0f;
ngon_center(c, bm, f);
BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
if( num_verts == 0 ) {
sv[0] = v[0] = l->v->co[0];
sv[1] = v[1] = l->v->co[1];
sv[2] = v[2] = l->v->co[2];
num_verts++;
} else {
area += AreaT3Dfl(v, c, l->v->co);
v[0] = l->v->co[0];
v[1] = l->v->co[1];
v[2] = l->v->co[2];
num_verts++;
}
}
area += AreaT3Dfl(v, c, sv);
return area;
}
/*
** extra face data (computed data)
*/
typedef struct tmp_face_ext {
BMFace *f; /* the face */
float c[3]; /* center */
union {
float area; /* area */
float perim; /* perimeter */
float d; /* 4th component of plane (the first three being the normal) */
struct Image *t; /* image pointer */
};
} tmp_face_ext;
/*
** Select similar faces, the choices are in the enum in source/blender/bmesh/bmesh_operators.h
** We select either similar faces based on material, image, area, perimeter, normal, or the coplanar faces
*/
void bmesh_similarfaces_exec(BMesh *bm, BMOperator *op)
{
BMIter fm_iter;
BMFace *fs, *fm;
BMOIter fs_iter;
int num_tex, num_sels = 0, num_total = 0, i = 0, idx = 0;
float angle = 0.0f;
tmp_face_ext *f_ext = NULL;
int *indices = NULL;
float t_no[3]; /* temporary normal */
int type = BMO_Get_Int(op, "type");
float thresh = BMO_Get_Float(op, "thresh");
num_total = BM_Count_Element(bm, BM_FACE);
/*
** The first thing to do is to iterate through all the the selected items and mark them since
** they will be in the selection anyway.
** This will increase performance, (especially when the number of originaly selected faces is high)
** so the overall complexity will be less than $O(mn)$ where is the total number of selected faces,
** and n is the total number of faces
*/
BMO_ITER(fs, &fs_iter, bm, op, "faces", BM_FACE) {
if (!BMO_TestFlag(bm, fs, FACE_MARK)) { /* is this really needed ? */
BMO_SetFlag(bm, fs, FACE_MARK);
num_sels++;
}
}
/* allocate memory for the selected faces indices and for all temporary faces */
indices = (int*)malloc(sizeof(int) * num_sels);
f_ext = (tmp_face_ext*)malloc(sizeof(tmp_face_ext) * num_total);
/* loop through all the faces and fill the faces/indices structure */
BM_ITER(fm, &fm_iter, bm, BM_FACES_OF_MESH, NULL) {
f_ext[i].f = fm;
if (BMO_TestFlag(bm, fm, FACE_MARK)) {
indices[idx] = i;
idx++;
}
i++;
}
/*
** Save us some computation burden: In case of perimeter/area/coplanar selection we compute
** only once.
*/
if( type == SIMFACE_PERIMETER || type == SIMFACE_AREA || type == SIMFACE_COPLANAR || type == SIMFACE_IMAGE ) {
for( i = 0; i < num_total; i++ ) {
switch( type ) {
case SIMFACE_PERIMETER:
/* set the perimeter */
f_ext[i].perim = ngon_perimeter(bm, f_ext[i].f);
break;
case SIMFACE_COPLANAR:
/* compute the center of the polygon */
ngon_center(f_ext[i].c, bm, f_ext[i].f);
/* normalize the polygon normal */
VecCopyf(t_no, f_ext[i].f->no);
Normalize(t_no);
/* compute the plane distance */
f_ext[i].d = Inpf(t_no, f_ext[i].c);
break;
case SIMFACE_AREA:
f_ext[i].area = ngon_fake_area(bm, f_ext[i].f);
break;
case SIMFACE_IMAGE:
f_ext[i].t = NULL;
if( CustomData_has_layer(&(bm->pdata), CD_MTEXPOLY) ) {
MTexPoly *mtpoly = CustomData_bmesh_get(&bm->pdata, f_ext[i].f->head.data, CD_MTEXPOLY);
f_ext[i].t = mtpoly->tpage;
}
break;
}
}
}
/* now select the rest (if any) */
//BM_ITER(fm, &fm_iter, bm, BM_FACES_OF_MESH, NULL) {
for( i = 0; i < num_total; i++ ) {
fm = f_ext[i].f;
if (!BMO_TestFlag(bm, fm, FACE_MARK)) {
//BMO_ITER(fs, &fs_iter, bm, op, "faces", BM_FACE) {
int cont = 1;
for( idx = 0; idx < num_sels && cont == 1; idx++ ) {
fs = f_ext[indices[idx]].f;
switch( type ) {
case SIMFACE_MATERIAL:
if( fm->mat_nr == fs->mat_nr ) {
BMO_SetFlag(bm, fm, FACE_MARK);
cont = 0;
}
break;
case SIMFACE_IMAGE:
if( f_ext[i].t == f_ext[indices[idx]].t ) {
BMO_SetFlag(bm, fm, FACE_MARK);
cont = 0;
}
break;
case SIMFACE_NORMAL:
angle = VecAngle2(fs->no, fm->no); /* if the angle between the normals -> 0 */
if( angle / 180.0 <= thresh ) {
BMO_SetFlag(bm, fm, FACE_MARK);
cont = 0;
}
break;
case SIMFACE_COPLANAR:
angle = VecAngle2(fs->no, fm->no); /* angle -> 0 */
if( angle / 180.0 <= thresh ) { /* and dot product difference -> 0 */
if( fabs(f_ext[i].d - f_ext[indices[idx]].d) <= thresh ) {
BMO_SetFlag(bm, fm, FACE_MARK);
cont = 0;
}
}
break;
case SIMFACE_AREA:
if( fabs(f_ext[i].area - f_ext[indices[idx]].area) <= thresh ) {
BMO_SetFlag(bm, fm, FACE_MARK);
cont = 0;
}
break;
case SIMFACE_PERIMETER:
if( fabs(f_ext[i].perim - f_ext[indices[idx]].perim) <= thresh ) {
BMO_SetFlag(bm, fm, FACE_MARK);
cont = 0;
}
break;
}
}
}
}
free(f_ext);
free(indices);
/* transfer all marked faces to the output slot */
BMO_Flag_To_Slot(bm, op, "faceout", FACE_MARK, BM_FACE);
}

View File

@@ -649,13 +649,6 @@ static int unified_findnearest(ViewContext *vc, BMVert **eve, BMEdge **eed, BMFa
/* FACES GROUP */
#define SIMFACE_MATERIAL 201
#define SIMFACE_IMAGE 202
#define SIMFACE_AREA 203
#define SIMFACE_PERIMETER 204
#define SIMFACE_NORMAL 205
#define SIMFACE_COPLANAR 206
static EnumPropertyItem prop_simface_types[] = {
{SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""},
{SIMFACE_IMAGE, "IMAGE", 0, "Image", ""},
@@ -666,160 +659,40 @@ static EnumPropertyItem prop_simface_types[] = {
{0, NULL, 0, NULL, NULL}
};
/* this as a way to compare the ares, perim of 2 faces thay will scale to different sizes
*0.5 so smaller faces arnt ALWAYS selected with a thresh of 1.0 */
#define SCALE_CMP(a,b) ((a+a*thresh >= b) && (a-(a*thresh*0.5) <= b))
static int similar_face_select__internal(Scene *scene, EditMesh *em, int mode)
{
#if 0
EditFace *efa, *base_efa=NULL;
unsigned int selcount=0; /*count how many new faces we select*/
/*deselcount, count how many deselected faces are left, so we can bail out early
also means that if there are no deselected faces, we can avoid a lot of looping */
unsigned int deselcount=0;
float thresh= scene->toolsettings->select_thresh;
short ok=0;
for(efa= em->faces.first; efa; efa= efa->next) {
if (!efa->h) {
if (efa->f & SELECT) {
efa->f1=1;
ok=1;
} else {
efa->f1=0;
deselcount++; /* a deselected face we may select later */
}
}
}
if (!ok || !deselcount) /* no data selected OR no more data to select */
return 0;
if (mode==SIMFACE_AREA) {
for(efa= em->faces.first; efa; efa= efa->next) {
efa->tmp.fp= EM_face_area(efa);
}
} else if (mode==SIMFACE_PERIMETER) {
for(efa= em->faces.first; efa; efa= efa->next) {
efa->tmp.fp= EM_face_perimeter(efa);
}
}
for(base_efa= em->faces.first; base_efa; base_efa= base_efa->next) {
if (base_efa->f1) { /* This was one of the faces originaly selected */
if (mode==SIMFACE_MATERIAL) { /* same material */
for(efa= em->faces.first; efa; efa= efa->next) {
if (
!(efa->f & SELECT) &&
!efa->h &&
base_efa->mat_nr == efa->mat_nr
) {
EM_select_face(efa, 1);
selcount++;
deselcount--;
if (!deselcount) /*have we selected all posible faces?, if so return*/
return selcount;
}
}
} else if (mode==SIMFACE_IMAGE) { /* same image */
MTFace *tf, *base_tf;
base_tf = (MTFace*)CustomData_em_get(&em->fdata, base_efa->data,
CD_MTFACE);
if(!base_tf)
return selcount;
for(efa= em->faces.first; efa; efa= efa->next) {
if (!(efa->f & SELECT) && !efa->h) {
tf = (MTFace*)CustomData_em_get(&em->fdata, efa->data,
CD_MTFACE);
if(base_tf->tpage == tf->tpage) {
EM_select_face(efa, 1);
selcount++;
deselcount--;
if (!deselcount) /*have we selected all posible faces?, if so return*/
return selcount;
}
}
}
} else if (mode==SIMFACE_AREA || mode==SIMFACE_PERIMETER) { /* same area OR same perimeter, both use the same temp var */
for(efa= em->faces.first; efa; efa= efa->next) {
if (
(!(efa->f & SELECT) && !efa->h) &&
SCALE_CMP(base_efa->tmp.fp, efa->tmp.fp)
) {
EM_select_face(efa, 1);
selcount++;
deselcount--;
if (!deselcount) /*have we selected all posible faces?, if so return*/
return selcount;
}
}
} else if (mode==SIMFACE_NORMAL) {
float angle;
for(efa= em->faces.first; efa; efa= efa->next) {
if (!(efa->f & SELECT) && !efa->h) {
angle= VecAngle2(base_efa->n, efa->n);
if (angle/180.0<=thresh) {
EM_select_face(efa, 1);
selcount++;
deselcount--;
if (!deselcount) /*have we selected all posible faces?, if so return*/
return selcount;
}
}
}
} else if (mode==SIMFACE_COPLANAR) { /* same planer */
float angle, base_dot, dot;
base_dot= Inpf(base_efa->cent, base_efa->n);
for(efa= em->faces.first; efa; efa= efa->next) {
if (!(efa->f & SELECT) && !efa->h) {
angle= VecAngle2(base_efa->n, efa->n);
if (angle/180.0<=thresh) {
dot=Inpf(efa->cent, base_efa->n);
if (fabs(base_dot-dot) <= thresh) {
EM_select_face(efa, 1);
selcount++;
deselcount--;
if (!deselcount) /*have we selected all posible faces?, if so return*/
return selcount;
}
}
}
}
}
}
} /* end base_efa loop */
return selcount;
#endif
}
static int similar_face_select_exec(bContext *C, wmOperator *op)
{
#if 0
Scene *scene= CTX_data_scene(C);
Object *obedit= CTX_data_edit_object(C);
Mesh *me= obedit->data;
EditMesh *em= BKE_mesh_get_editmesh(me);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_edit_object(C);
BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
BMOperator bmop;
int selcount = similar_face_select__internal(scene, em, RNA_int_get(op->ptr, "type"));
if (selcount) {
/* here was an edge-mode only select flush case, has to be generalized */
EM_selectmode_flush(em);
WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
BKE_mesh_end_editmesh(me, em);
return OPERATOR_FINISHED;
}
BKE_mesh_end_editmesh(me, em);
#endif
return OPERATOR_CANCELLED;
/* get the type from RNA */
int type = RNA_enum_get(op->ptr, "type");
float thresh = scene->toolsettings->select_thresh;
/* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
EDBM_InitOpf(em, &bmop, op, "similarfaces faces=%hf type=%d thresh=%f", BM_SELECT, type, thresh);
/* execute the operator */
BMO_Exec_Op(em->bm, &bmop);
/* clear the existing selection */
EDBM_clear_flag_all(em, BM_SELECT);
/* select the output */
BMO_HeaderFlag_Buffer(em->bm, &bmop, "faceout", BM_SELECT, BM_ALL);
/* finish the operator */
if( !EDBM_FinishOp(em, &bmop, op, 1) )
return OPERATOR_CANCELLED;
/* dependencies graph and notification stuff */
DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_GEOM_SELECT, ob);
/* we succeeded */
return OPERATOR_FINISHED;
}
/* ***************************************************** */