Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/bmesh/operators/bevel.c')
-rw-r--r--source/blender/bmesh/operators/bevel.c825
1 files changed, 825 insertions, 0 deletions
diff --git a/source/blender/bmesh/operators/bevel.c b/source/blender/bmesh/operators/bevel.c
new file mode 100644
index 00000000000..717ba0a7621
--- /dev/null
+++ b/source/blender/bmesh/operators/bevel.c
@@ -0,0 +1,825 @@
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_memarena.h"
+#include "BLI_blenlib.h"
+#include "BLI_array.h"
+#include "BLI_math.h"
+#include "BLI_array.h"
+#include "BLI_utildefines.h"
+#include "BLI_smallhash.h"
+
+#include "bmesh.h"
+#include "bmesh_operators_private.h"
+
+#define BEVEL_FLAG 1
+#define BEVEL_DEL 2
+#define FACE_NEW 4
+#define EDGE_OLD 8
+#define FACE_OLD 16
+#define FACE_DONE 32
+#define VERT_OLD 64
+#define FACE_SPAN 128
+#define FACE_HOLE 256
+
+typedef struct LoopTag {
+ BMVert *newv;
+} LoopTag;
+
+typedef struct EdgeTag {
+ BMVert *newv1, *newv2;
+} EdgeTag;
+
+static void calc_corner_co(BMesh *bm, BMLoop *l, float *co, float fac)
+{
+ float no[3], /*tan[3]*,*/ vec1[3], vec2[3], v1[3], v2[3], v3[3], v4[3];
+ /*float p1[3], p2[3], w[3];
+ float l1, l2;*/
+ int /*ret,*/ inv=0;
+
+ if (l->f->len > 2) {
+ copy_v3_v3(v1, l->prev->v->co);
+ copy_v3_v3(v2, l->v->co);
+ copy_v3_v3(v3, l->v->co);
+ copy_v3_v3(v4, l->next->v->co);
+ } else {
+ BMIter iter;
+ BMLoop *l2;
+ float up[3] = {0.0f, 0.0f, 1.0f};
+
+ copy_v3_v3(v1, l->prev->v->co);
+ copy_v3_v3(v2, l->v->co);
+ copy_v3_v3(v3, l->v->co);
+
+ BM_ITER(l2, &iter, bm, BM_LOOPS_OF_VERT, l->v) {
+ if (l2->f != l->f) {
+ copy_v3_v3(v4, BM_OtherEdgeVert(l2->e, l2->next->v)->co);
+ break;
+ }
+ }
+
+ sub_v3_v3v3(vec1, v1, v2);
+ sub_v3_v3v3(vec2, v4, v3);
+
+ cross_v3_v3v3(no, vec1, vec2);
+ if (dot_v3v3(no, no) == 0.0f) {
+ no[0] = no[1] = 0.0f; no[2] = -1.0f;
+ }
+
+ inv = dot_v3v3(no, up) < 0.0f;
+ }
+
+ /*calculate normal*/
+ sub_v3_v3v3(vec1, v1, v2);
+ sub_v3_v3v3(vec2, v4, v3);
+
+#if 0
+ cross_v3_v3v3(no, vec2, vec1);
+ normalize_v3(no);
+
+ if (dot_v3v3(no, no) < FLT_EPSILON*10) {
+ copy_v3_v3(no, l->f->no);
+ }
+
+ if (dot_v3v3(no, no) < FLT_EPSILON*10) {
+ no[0] = 0.0; no[1] = 0.0; no[2] = 1.0f;
+ }
+
+ /*compute offsets*/
+ l1 = len_v3(vec1)*fac; //(1.0-(cos(angle_v3v3(vec1, vec2))*0.5+0.5))
+ l2 = len_v3(vec2)*fac;
+
+ l2 = (l1 + l2)*0.5;
+ l1 = l2;
+ if (dot_v3v3(no, l->f->no) < 0.0) {
+ negate_v3(no);
+ }
+
+ /*compute tangent and offset first edge*/
+ cross_v3_v3v3(tan, vec1, no);
+ normalize_v3(tan);
+
+ mul_v3_fl(tan, l1);
+
+ add_v3_v3(v1, tan);
+ add_v3_v3(v2, tan);
+
+ /*compute tangent and offset second edge*/
+ cross_v3_v3v3(tan, no, vec2);
+ normalize_v3(tan);
+
+ mul_v3_fl(tan, l2);
+
+ add_v3_v3(v3, tan);
+ add_v3_v3(v4, tan);
+
+ /*compute intersection*/
+ ret = isect_line_line_v3(v1, v2, v3, v4, p1, p2);
+
+ if (ret==1) {
+ copy_v3_v3(co, p1);
+ } else if (ret==2) {
+ add_v3_v3v3(co, p1, p2);
+ mul_v3_fl(co, 0.5);
+ } else { /*colinear case*/
+ add_v3_v3v3(co, v2, v3);
+ mul_v3_fl(co, 0.5);
+ }
+#else
+ /*oddly, this simplistic method seems to work the best*/
+ add_v3_v3(vec1, vec2);
+ mul_v3_fl(vec1, fac * 0.5);
+
+ if (inv)
+ negate_v3(vec1);
+
+ add_v3_v3v3(co, vec1, l->v->co);
+#endif
+}
+
+#define ETAG_SET(e, v, nv) (v) == (e)->v1 ? (etags[BM_GetIndex((e))].newv1 = (nv)) : (etags[BM_GetIndex((e))].newv2 = (nv))
+#define ETAG_GET(e, v) ((v) == (e)->v1 ? (etags[BM_GetIndex((e))].newv1) : (etags[BM_GetIndex((e))].newv2))
+
+void bmesh_bevel_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter siter;
+ BMIter iter;
+ BMEdge *e;
+ BMVert *v;
+ BMFace **faces = NULL, *f;
+ LoopTag *tags=NULL, *tag;
+ EdgeTag *etags = NULL;
+ BMVert **verts = NULL;
+ BMEdge **edges = NULL;
+ BLI_array_declare(faces);
+ BLI_array_declare(tags);
+ BLI_array_declare(etags);
+ BLI_array_declare(verts);
+ BLI_array_declare(edges);
+ SmallHash hash;
+ float fac = BMO_Get_Float(op, "percent");
+ int i, li, has_elens, HasMDisps = CustomData_has_layer(&bm->ldata, CD_MDISPS);
+
+ has_elens = CustomData_has_layer(&bm->edata, CD_PROP_FLT) && BMO_Get_Int(op, "uselengths");
+ if (has_elens) {
+ li = BMO_Get_Int(op, "lengthlayer");
+ }
+
+ BLI_smallhash_init(&hash);
+
+ BMO_ITER(e, &siter, bm, op, "geom", BM_EDGE) {
+ BMO_SetFlag(bm, e, BEVEL_FLAG|BEVEL_DEL);
+ BMO_SetFlag(bm, e->v1, BEVEL_FLAG|BEVEL_DEL);
+ BMO_SetFlag(bm, e->v2, BEVEL_FLAG|BEVEL_DEL);
+
+ if (BM_Edge_FaceCount(e) < 2) {
+ BMO_ClearFlag(bm, e, BEVEL_DEL);
+ BMO_ClearFlag(bm, e->v1, BEVEL_DEL);
+ BMO_ClearFlag(bm, e->v2, BEVEL_DEL);
+ }
+#if 0
+ if (BM_Edge_FaceCount(e) == 0) {
+ BMVert *verts[2] = {e->v1, e->v2};
+ BMEdge *edges[2] = {e, BM_Make_Edge(bm, e->v1, e->v2, e, 0)};
+
+ BMO_SetFlag(bm, edges[1], BEVEL_FLAG);
+ BM_Make_Face(bm, verts, edges, 2, 0);
+ }
+#endif
+ }
+
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ BMO_SetFlag(bm, v, VERT_OLD);
+ }
+
+#if 0
+ //a bit of cleaner code that, alas, doens't work.
+ /*build edge tags*/
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (BMO_TestFlag(bm, e->v1, BEVEL_FLAG) || BMO_TestFlag(bm, e->v2, BEVEL_FLAG)) {
+ BMIter liter;
+ BMLoop *l;
+
+ if (!BMO_TestFlag(bm, e, EDGE_OLD)) {
+ BM_SetIndex(e, BLI_array_count(etags));
+ BLI_array_growone(etags);
+
+ BMO_SetFlag(bm, e, EDGE_OLD);
+ }
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_EDGE, e) {
+ BMLoop *l2;
+ BMIter liter2;
+
+ if (BMO_TestFlag(bm, l->f, BEVEL_FLAG))
+ continue;
+
+ BM_ITER(l2, &liter2, bm, BM_LOOPS_OF_FACE, l->f) {
+ BM_SetIndex(l2, BLI_array_count(tags));
+ BLI_array_growone(tags);
+
+ if (!BMO_TestFlag(bm, l2->e, EDGE_OLD)) {
+ BM_SetIndex(l2->e, BLI_array_count(etags));
+ BLI_array_growone(etags);
+
+ BMO_SetFlag(bm, l2->e, EDGE_OLD);
+ }
+ }
+
+ BMO_SetFlag(bm, l->f, BEVEL_FLAG);
+ BLI_array_append(faces, l->f);
+ }
+ } else {
+ BM_SetIndex(e, -1);
+ }
+ }
+#endif
+
+ /*create and assign looptag structures*/
+ BMO_ITER(e, &siter, bm, op, "geom", BM_EDGE) {
+ BMLoop *l;
+ BMIter liter;
+
+ BMO_SetFlag(bm, e->v1, BEVEL_FLAG|BEVEL_DEL);
+ BMO_SetFlag(bm, e->v2, BEVEL_FLAG|BEVEL_DEL);
+
+ if (BM_Edge_FaceCount(e) < 2) {
+ BMO_ClearFlag(bm, e, BEVEL_DEL);
+ BMO_ClearFlag(bm, e->v1, BEVEL_DEL);
+ BMO_ClearFlag(bm, e->v2, BEVEL_DEL);
+ }
+
+ if (!BLI_smallhash_haskey(&hash, (intptr_t)e)) {
+ BLI_array_growone(etags);
+ BM_SetIndex(e, BLI_array_count(etags)-1);
+ BLI_smallhash_insert(&hash, (intptr_t)e, NULL);
+ BMO_SetFlag(bm, e, EDGE_OLD);
+ }
+
+ /*find all faces surrounding e->v1 and, e->v2*/
+ for (i=0; i<2; i++) {
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_VERT, i?e->v2:e->v1) {
+ BMLoop *l2;
+ BMIter liter2;
+
+ /*see if we've already processed this loop's face*/
+ if (BLI_smallhash_haskey(&hash, (intptr_t)l->f))
+ continue;
+
+ /*create tags for all loops in l->f*/
+ BM_ITER(l2, &liter2, bm, BM_LOOPS_OF_FACE, l->f) {
+ BLI_array_growone(tags);
+ BM_SetIndex(l2, BLI_array_count(tags)-1);
+
+ if (!BLI_smallhash_haskey(&hash, (intptr_t)l2->e)) {
+ BLI_array_growone(etags);
+ BM_SetIndex(l2->e, BLI_array_count(etags)-1);
+ BLI_smallhash_insert(&hash, (intptr_t)l2->e, NULL);
+ BMO_SetFlag(bm, l2->e, EDGE_OLD);
+ }
+ }
+
+ BLI_smallhash_insert(&hash, (intptr_t)l->f, NULL);
+ BMO_SetFlag(bm, l->f, BEVEL_FLAG);
+ BLI_array_append(faces, l->f);
+ }
+ }
+ }
+
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ BMIter eiter;
+
+ if (!BMO_TestFlag(bm, v, BEVEL_FLAG))
+ continue;
+
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
+ if (!BMO_TestFlag(bm, e, BEVEL_FLAG) && !ETAG_GET(e, v)) {
+ BMVert *v2;
+ float co[3];
+
+ v2 = BM_OtherEdgeVert(e, v);
+ sub_v3_v3v3(co, v2->co, v->co);
+ if (has_elens) {
+ float elen = *(float*)CustomData_bmesh_get_n(&bm->edata, e->head.data, CD_PROP_FLT, li);
+
+ normalize_v3(co);
+ mul_v3_fl(co, elen);
+ }
+
+ mul_v3_fl(co, fac);
+ add_v3_v3(co, v->co);
+
+ v2 = BM_Make_Vert(bm, co, v);
+ ETAG_SET(e, v, v2);
+ }
+ }
+ }
+
+ for (i=0; i<BLI_array_count(faces); i++) {
+ BMLoop *l;
+ BMIter liter;
+
+ BMO_SetFlag(bm, faces[i], FACE_OLD);
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, faces[i]) {
+ float co[3];
+
+ if (BMO_TestFlag(bm, l->e, BEVEL_FLAG)) {
+ if (BMO_TestFlag(bm, l->prev->e, BEVEL_FLAG))
+ {
+ tag = tags + BM_GetIndex(l);
+ calc_corner_co(bm, l, co, fac);
+ tag->newv = BM_Make_Vert(bm, co, l->v);
+ } else {
+ tag = tags + BM_GetIndex(l);
+ tag->newv = ETAG_GET(l->prev->e, l->v);
+
+ if (!tag->newv) {
+ sub_v3_v3v3(co, l->prev->v->co, l->v->co);
+ if (has_elens) {
+ float elen = *(float*)CustomData_bmesh_get_n(&bm->edata, l->prev->e->head.data, CD_PROP_FLT, li);
+
+ normalize_v3(co);
+ mul_v3_fl(co, elen);
+ }
+
+ mul_v3_fl(co, fac);
+ add_v3_v3(co, l->v->co);
+
+ tag->newv = BM_Make_Vert(bm, co, l->v);
+
+ ETAG_SET(l->prev->e, l->v, tag->newv);
+ }
+ }
+ } else if (BMO_TestFlag(bm, l->v, BEVEL_FLAG)) {
+ tag = tags + BM_GetIndex(l);
+ tag->newv = ETAG_GET(l->e, l->v);
+
+ if (!tag->newv) {
+ sub_v3_v3v3(co, l->next->v->co, l->v->co);
+ if (has_elens) {
+ float elen = *(float*)CustomData_bmesh_get_n(&bm->edata, l->e->head.data, CD_PROP_FLT, li);
+
+ normalize_v3(co);
+ mul_v3_fl(co, elen);
+ }
+
+ mul_v3_fl(co, fac);
+ add_v3_v3(co, l->v->co);
+
+ tag = tags + BM_GetIndex(l);
+ tag->newv = BM_Make_Vert(bm, co, l->v);
+
+ ETAG_SET(l->e, l->v, tag->newv);
+ }
+ } else {
+ tag = tags + BM_GetIndex(l);
+ tag->newv = l->v;
+ BMO_ClearFlag(bm, l->v, BEVEL_DEL);
+ }
+ }
+ }
+
+ /*create new faces inset from original faces*/
+ for (i=0; i<BLI_array_count(faces); i++) {
+ BMLoop *l;
+ BMIter liter;
+ BMFace *f;
+ BMVert *lastv=NULL, *firstv=NULL;
+
+ BMO_SetFlag(bm, faces[i], BEVEL_DEL);
+
+ BLI_array_empty(verts);
+ BLI_array_empty(edges);
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, faces[i]) {
+ BMVert *v2;
+
+ tag = tags + BM_GetIndex(l);
+ BLI_array_append(verts, tag->newv);
+
+ if (!firstv)
+ firstv = tag->newv;
+
+ if (lastv) {
+ e = BM_Make_Edge(bm, lastv, tag->newv, l->e, 1);
+ BM_Copy_Attributes(bm, bm, l->prev->e, e);
+ BLI_array_append(edges, e);
+ }
+ lastv=tag->newv;
+
+ v2 = ETAG_GET(l->e, l->next->v);
+
+ tag = tags + BM_GetIndex(l->next);
+ if (!BMO_TestFlag(bm, l->e, BEVEL_FLAG) && v2 && v2 != tag->newv) {
+ BLI_array_append(verts, v2);
+
+ e = BM_Make_Edge(bm, lastv, v2, l->e, 1);
+ BM_Copy_Attributes(bm, bm, l->e, e);
+
+ BLI_array_append(edges, e);
+ lastv = v2;
+ }
+ }
+
+ e = BM_Make_Edge(bm, firstv, lastv, bm_firstfaceloop(faces[i])->e, 1);
+ if (bm_firstfaceloop(faces[i])->prev->e != e)
+ BM_Copy_Attributes(bm, bm, bm_firstfaceloop(faces[i])->prev->e, e);
+ BLI_array_append(edges, e);
+
+ f = BM_Make_Ngon(bm, verts[0], verts[1], edges, BLI_array_count(edges), 0);
+ if (!f) {
+ printf("eek!!\n");
+ continue;
+ }
+
+ BMO_SetFlag(bm, f, FACE_NEW);
+ }
+
+ for (i=0; i<BLI_array_count(faces); i++) {
+ BMLoop *l;
+ BMIter liter;
+ int j;
+
+ /*create quad spans between split edges*/
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, faces[i]) {
+ BMVert *v1=NULL, *v2=NULL, *v3=NULL, *v4=NULL;
+
+ if (!BMO_TestFlag(bm, l->e, BEVEL_FLAG))
+ continue;
+
+ v1 = tags[BM_GetIndex(l)].newv;
+ v2 = tags[BM_GetIndex(l->next)].newv;
+ if (l->radial_next != l) {
+ v3 = tags[BM_GetIndex(l->radial_next)].newv;
+ if (l->radial_next->next->v == l->next->v) {
+ v4 = v3;
+ v3 = tags[BM_GetIndex(l->radial_next->next)].newv;
+ } else {
+ v4 = tags[BM_GetIndex(l->radial_next->next)].newv;
+ }
+ } else {
+ /*the loop is on a boundary*/
+ v3 = l->next->v;
+ v4 = l->v;
+
+ for (j=0; j<2; j++) {
+ BMIter eiter;
+ BMVert *v = j ? v4 : v3;
+
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
+ if (!BM_Vert_In_Edge(e, v3) || !BM_Vert_In_Edge(e, v4))
+ continue;
+
+ if (!BMO_TestFlag(bm, e, BEVEL_FLAG) && BMO_TestFlag(bm, e, EDGE_OLD)) {
+ BMVert *vv;
+
+ vv = ETAG_GET(e, v);
+ if (!vv || BMO_TestFlag(bm, vv, BEVEL_FLAG))
+ continue;
+
+ if (j)
+ v1 = vv;
+ else
+ v2 = vv;
+ break;
+ }
+ }
+ }
+
+ BMO_ClearFlag(bm, v3, BEVEL_DEL);
+ BMO_ClearFlag(bm, v4, BEVEL_DEL);
+ }
+
+ if (v1 != v2 && v2 != v3 && v3 != v4) {
+ BMIter liter2;
+ BMLoop *l2, *l3;
+ BMEdge *e1, *e2;
+ float d1, d2, *d3;
+
+ f = BM_Make_QuadTri(bm, v4, v3, v2, v1, l->f, 1);
+
+ e1 = BM_Edge_Exist(v4, v3);
+ e2 = BM_Edge_Exist(v2, v1);
+ BM_Copy_Attributes(bm, bm, l->e, e1);
+ BM_Copy_Attributes(bm, bm, l->e, e2);
+
+ /*set edge lengths of cross edges as the average of the cross edges they're based on*/
+ if (has_elens) {
+#if 0 /* angle happens not to be used. why? - not sure it just isnt - campbell. leave this in incase we need to use it later */
+ float ang;
+#endif
+ e1 = BM_Edge_Exist(v1, v4);
+ e2 = BM_Edge_Exist(v2, v3);
+
+ if (l->radial_next->v == l->v) {
+ l2 = l->radial_next->prev;
+ l3 = l->radial_next->next;
+ } else {
+ l2 = l->radial_next->next;
+ l3 = l->radial_next->prev;
+ }
+
+ d3 = CustomData_bmesh_get_n(&bm->edata, e1->head.data, CD_PROP_FLT, li);
+ d1 = *(float*)CustomData_bmesh_get_n(&bm->edata, l->prev->e->head.data, CD_PROP_FLT, li);
+ d2 = *(float*)CustomData_bmesh_get_n(&bm->edata, l2->e->head.data, CD_PROP_FLT, li);
+#if 0
+ ang = angle_v3v3v3(l->prev->v->co, l->v->co, BM_OtherEdgeVert(l2->e, l->v)->co);
+#endif
+ *d3 = (d1+d2)*0.5f;
+
+ d3 = CustomData_bmesh_get_n(&bm->edata, e2->head.data, CD_PROP_FLT, li);
+ d1 = *(float*)CustomData_bmesh_get_n(&bm->edata, l->next->e->head.data, CD_PROP_FLT, li);
+ d2 = *(float*)CustomData_bmesh_get_n(&bm->edata, l3->e->head.data, CD_PROP_FLT, li);
+#if 0
+ ang = angle_v3v3v3(BM_OtherEdgeVert(l->next->e, l->next->v)->co, l->next->v->co, BM_OtherEdgeVert(l3->e, l->next->v)->co);
+#endif
+ *d3 = (d1+d2)*0.5f;
+ }
+
+ if (!f) {
+ fprintf(stderr, "%s: face index out of range! (bmesh internal error)\n", __func__);
+ continue;
+ }
+
+ BMO_SetFlag(bm, f, FACE_NEW|FACE_SPAN);
+
+ /*un-tag edges in f for deletion*/
+ BM_ITER(l2, &liter2, bm, BM_LOOPS_OF_FACE, f) {
+ BMO_ClearFlag(bm, l2->e, BEVEL_DEL);
+ }
+ } else {
+ f = NULL;
+ }
+ }
+ }
+
+ /*fill in holes at vertices*/
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ BMIter eiter;
+ BMVert *vv, *vstart=NULL, *lastv=NULL;
+ SmallHash tmphash;
+ int rad, insorig=0, err=0;
+
+ BLI_smallhash_init(&tmphash);
+
+ if (!BMO_TestFlag(bm, v, BEVEL_FLAG))
+ continue;
+
+ BLI_array_empty(verts);
+ BLI_array_empty(edges);
+
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
+ BMIter liter;
+ BMVert *v1=NULL, *v2=NULL;
+ BMLoop *l;
+
+ if (BM_Edge_FaceCount(e) < 2)
+ insorig = 1;
+
+ rad = 0;
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_EDGE, e) {
+ if (!BMO_TestFlag(bm, l->f, FACE_OLD))
+ continue;
+
+ rad++;
+
+ if (l->v == v)
+ tag = tags + BM_GetIndex(l);
+ else
+ tag = tags + BM_GetIndex(l->next);
+
+ if (!v1)
+ v1 = tag->newv;
+ else if (!v2)
+ v2 = tag->newv;
+ }
+
+ if (rad < 2)
+ insorig = 1;
+
+ if (!v1)
+ v1 = ETAG_GET(e, v);
+ if (!v2 || v1 == v2)
+ v2 = ETAG_GET(e, v);
+
+ if (v1) {
+ if (!BLI_smallhash_haskey(&tmphash, (intptr_t)v1)) {
+ BLI_array_append(verts, v1);
+ BLI_smallhash_insert(&tmphash, (intptr_t)v1, NULL);
+ }
+
+ if (v2 && v1 != v2 && !BLI_smallhash_haskey(&tmphash, (intptr_t)v2)) {
+ BLI_array_append(verts, v2);
+ BLI_smallhash_insert(&tmphash, (intptr_t)v2, NULL);
+ }
+ }
+ }
+
+ if (!BLI_array_count(verts))
+ continue;
+
+ if (insorig) {
+ BLI_array_append(verts, v);
+ BLI_smallhash_insert(&tmphash, (intptr_t)v, NULL);
+ }
+
+ /*find edges that exist between vertices in verts. this is basically
+ a topological walk of the edges connecting them.*/
+ vstart = vstart ? vstart : verts[0];
+ vv = vstart;
+ do {
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, vv) {
+ BMVert *vv2 = BM_OtherEdgeVert(e, vv);
+
+ if (vv2 != lastv && BLI_smallhash_haskey(&tmphash, (intptr_t)vv2)) {
+ /*if we've go over the same vert twice, break out of outer loop*/
+ if (BLI_smallhash_lookup(&tmphash, (intptr_t)vv2) != NULL) {
+ e = NULL;
+ err = 1;
+ break;
+ }
+
+ /*use self pointer as tag*/
+ BLI_smallhash_remove(&tmphash, (intptr_t)vv2);
+ BLI_smallhash_insert(&tmphash, (intptr_t)vv2, vv2);
+
+ lastv = vv;
+ BLI_array_append(edges, e);
+ vv = vv2;
+ break;
+ }
+ }
+ if (e == NULL)
+ break;
+ } while (vv != vstart);
+
+ if (err)
+ continue;
+
+ /*there may not be a complete loop of edges, so start again and make
+ final edge afterwards. in this case, the previous loop worked to
+ find one of the two edges at the extremes.*/
+ if (vv != vstart) {
+ /*undo previous tagging*/
+ for (i=0; i<BLI_array_count(verts); i++) {
+ BLI_smallhash_remove(&tmphash, (intptr_t)verts[i]);
+ BLI_smallhash_insert(&tmphash, (intptr_t)verts[i], NULL);
+ }
+
+ vstart = vv;
+ lastv = NULL;
+ BLI_array_empty(edges);
+ do {
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, vv) {
+ BMVert *vv2 = BM_OtherEdgeVert(e, vv);
+
+ if (vv2 != lastv && BLI_smallhash_haskey(&tmphash, (intptr_t)vv2)) {
+ /*if we've go over the same vert twice, break out of outer loop*/
+ if (BLI_smallhash_lookup(&tmphash, (intptr_t)vv2) != NULL) {
+ e = NULL;
+ err = 1;
+ break;
+ }
+
+ /*use self pointer as tag*/
+ BLI_smallhash_remove(&tmphash, (intptr_t)vv2);
+ BLI_smallhash_insert(&tmphash, (intptr_t)vv2, vv2);
+
+ lastv = vv;
+ BLI_array_append(edges, e);
+ vv = vv2;
+ break;
+ }
+ }
+ if (e == NULL)
+ break;
+ } while (vv != vstart);
+
+ if (!err) {
+ e = BM_Make_Edge(bm, vv, vstart, NULL, 1);
+ BLI_array_append(edges, e);
+ }
+ }
+
+ if (err)
+ continue;
+
+ if (BLI_array_count(edges) >= 3) {
+ BMFace *f;
+
+ if (BM_Face_Exists(bm, verts, BLI_array_count(verts), &f))
+ continue;
+
+ f = BM_Make_Ngon(bm, lastv, vstart, edges, BLI_array_count(edges), 0);
+ if (!f) {
+ fprintf(stderr, "%s: in bevel vert fill! (bmesh internal error)\n", __func__);
+ } else {
+ BMO_SetFlag(bm, f, FACE_NEW|FACE_HOLE);
+ }
+ }
+ BLI_smallhash_release(&tmphash);
+ }
+
+ /*copy over customdata*/
+ for (i=0; i<BLI_array_count(faces); i++) {
+ BMLoop *l;
+ BMIter liter;
+ BMFace *f = faces[i];
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ BMLoop *l2;
+ BMIter liter2;
+
+ tag = tags + BM_GetIndex(l);
+ if (!tag->newv)
+ continue;
+
+ BM_ITER(l2, &liter2, bm, BM_LOOPS_OF_VERT, tag->newv) {
+ if (!BMO_TestFlag(bm, l2->f, FACE_NEW) || (l2->v != tag->newv && l2->v != l->v))
+ continue;
+
+ if (tag->newv != l->v || HasMDisps) {
+ BM_Copy_Attributes(bm, bm, l->f, l2->f);
+ BM_loop_interp_from_face(bm, l2, l->f, 1, 1);
+ } else {
+ BM_Copy_Attributes(bm, bm, l->f, l2->f);
+ BM_Copy_Attributes(bm, bm, l, l2);
+ }
+
+ if (HasMDisps) {
+ BMLoop *l3;
+ BMIter liter3;
+
+ BM_ITER(l3, &liter3, bm, BM_LOOPS_OF_FACE, l2->f) {
+ BM_loop_interp_multires(bm, l3, l->f);
+ }
+ }
+ }
+ }
+ }
+
+ /*handle vertices along boundary edges*/
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (BMO_TestFlag(bm, v, VERT_OLD) && BMO_TestFlag(bm, v, BEVEL_FLAG) && !BMO_TestFlag(bm, v, BEVEL_DEL)) {
+ BMLoop *l;
+ BMLoop *lorig=NULL;
+ BMIter liter;
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_VERT, v) {
+ // BMIter liter2;
+ // BMLoop *l2 = l->v == v ? l : l->next, *l3;
+
+ if (BMO_TestFlag(bm, l->f, FACE_OLD)) {
+ lorig = l;
+ break;
+ }
+ }
+
+ if (!lorig)
+ continue;
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_VERT, v) {
+ BMLoop *l2 = l->v == v ? l : l->next;
+
+ BM_Copy_Attributes(bm, bm, lorig->f, l2->f);
+ BM_Copy_Attributes(bm, bm, lorig, l2);
+ }
+ }
+ }
+#if 0
+ /*clean up any remaining 2-edged faces*/
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ if (f->len == 2) {
+ BMFace *faces[2] = {f, bm_firstfaceloop(f)->radial_next->f};
+
+ if (faces[0] == faces[1])
+ BM_Kill_Face(bm, f);
+ else
+ BM_Join_Faces(bm, faces, 2);
+ }
+ }
+#endif
+
+ BMO_CallOpf(bm, "del geom=%fv context=%i", BEVEL_DEL, DEL_VERTS);
+
+ /*clean up any edges that might not get properly deleted*/
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (BMO_TestFlag(bm, e, EDGE_OLD) && !e->l)
+ BMO_SetFlag(bm, e, BEVEL_DEL);
+ }
+
+ BMO_CallOpf(bm, "del geom=%fe context=%i", BEVEL_DEL, DEL_EDGES);
+ BMO_CallOpf(bm, "del geom=%ff context=%i", BEVEL_DEL, DEL_FACES);
+
+ BLI_smallhash_release(&hash);
+ BLI_array_free(tags);
+ BLI_array_free(etags);
+ BLI_array_free(verts);
+ BLI_array_free(edges);
+ BLI_array_free(faces);
+
+ BMO_Flag_To_Slot(bm, op, "face_spans", FACE_SPAN, BM_FACE);
+ BMO_Flag_To_Slot(bm, op, "face_holes", FACE_HOLE, BM_FACE);
+}