From 1216fe7f2134af2bae48e7eab892e34c29af0d28 Mon Sep 17 00:00:00 2001 From: Joseph Eagar Date: Thu, 17 Mar 2011 22:59:54 +0000 Subject: [PATCH] =bmesh= Bevel! Implemented bevel (from scratch). Man is this tool way cooler then I thought it was. Note that uv/vcol interpolation is working (loop level data) but vert/edge data (like vgroups) likely still needs work. --- source/blender/blenkernel/intern/BME_tools.c | 3 - source/blender/blenlib/BLI_smallhash.h | 19 +- source/blender/blenlib/intern/math_geom.c | 2 +- source/blender/bmesh/CMakeLists.txt | 1 + source/blender/bmesh/bmesh.h | 11 +- source/blender/bmesh/intern/bmesh_interp.c | 90 ++- source/blender/bmesh/intern/bmesh_opdefines.c | 17 + .../bmesh/intern/bmesh_operators_private.h | 1 + source/blender/bmesh/operators/bevel.c | 704 ++++++++++++++++++ source/blender/editors/mesh/bmesh_tools.c | 53 ++ source/blender/editors/mesh/loopcut.c | 5 + source/blender/editors/mesh/mesh_intern.h | 1 + source/blender/editors/mesh/mesh_ops.c | 2 + .../editors/space_view3d/view3d_edit.c | 2 +- source/blender/editors/uvedit/uvedit_ops.c | 2 +- source/blender/modifiers/intern/MOD_util.c | 2 +- 16 files changed, 895 insertions(+), 20 deletions(-) create mode 100644 source/blender/bmesh/operators/bevel.c diff --git a/source/blender/blenkernel/intern/BME_tools.c b/source/blender/blenkernel/intern/BME_tools.c index 9dd4669ba1f..8efc2d0e955 100644 --- a/source/blender/blenkernel/intern/BME_tools.c +++ b/source/blender/blenkernel/intern/BME_tools.c @@ -41,11 +41,8 @@ #include "DNA_object_types.h" #include "BLI_math.h" -<<<<<<< .working #include "BLI_cellalloc.h" -======= #include "BLI_utildefines.h" ->>>>>>> .merge-right.r35190 #include "BKE_bmesh.h" diff --git a/source/blender/blenlib/BLI_smallhash.h b/source/blender/blenlib/BLI_smallhash.h index 2ab365eea0e..a9b0e34bf89 100755 --- a/source/blender/blenlib/BLI_smallhash.h +++ b/source/blender/blenlib/BLI_smallhash.h @@ -59,7 +59,7 @@ typedef struct SmallHash { #define CELL_FREE ((void*)0x7FFFFFFD) #define NONZERO(n) ((n) + !(n)) -#define HASHNEXT(h, hoff) ((h) + ((hoff=NONZERO(hoff*2)+1), hoff)) +#define HASHNEXT(h, hoff) ABS(((h) + ((hoff=NONZERO(hoff*2)+1), hoff))) BM_INLINE void BLI_smallhash_init(SmallHash *hash) { @@ -92,7 +92,9 @@ BM_INLINE void BLI_smallhash_release(SmallHash *hash) BM_INLINE void BLI_smallhash_insert(SmallHash *hash, intptr_t key, void *item) { int h, hoff=1; - + + key = ABS(key); + if (hash->size < hash->used*3) { int newsize = hashsizes[++hash->curhash]; entry *tmp; @@ -145,7 +147,10 @@ BM_INLINE void BLI_smallhash_insert(SmallHash *hash, intptr_t key, void *item) BM_INLINE void BLI_smallhash_remove(SmallHash *hash, intptr_t key) { - int h = key, hoff=1; + int h, hoff=1; + + key = ABS(key); + h = key; while (hash->table[h % hash->size].key != key || hash->table[h % hash->size].val == CELL_UNUSED) @@ -162,7 +167,10 @@ BM_INLINE void BLI_smallhash_remove(SmallHash *hash, intptr_t key) BM_INLINE void *BLI_smallhash_lookup(SmallHash *hash, intptr_t key) { - int h = key, hoff=1; + int h, hoff=1; + + key = ABS(key); + h = key; if (!hash->table) return NULL; @@ -181,7 +189,8 @@ BM_INLINE void *BLI_smallhash_lookup(SmallHash *hash, intptr_t key) BM_INLINE int BLI_smallhash_haskey(SmallHash *hash, intptr_t key) { - int h = key, hoff=1; + int h = ABS(key), hoff=1; + key = ABS(key); if (!hash->table) return 0; diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 2d4935ed4a6..4f0e7d10dd5 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -905,7 +905,7 @@ int isect_line_line_v3(float v1[3], float v2[3], float v3[3], float v4[3], float normalize_v3_v3(dir1, a); normalize_v3_v3(dir2, b); d = dot_v3v3(dir1, dir2); - if (d == 1.0f || d == -1.0f) { + if (d >= 1.0-FLT_EPSILON*10 || d <= -1.0 + FLT_EPSILON*10) { /* colinear */ return 0; } diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt index 870cfa66a61..c16b1206222 100644 --- a/source/blender/bmesh/CMakeLists.txt +++ b/source/blender/bmesh/CMakeLists.txt @@ -58,6 +58,7 @@ set(INC ) set(SRC + operators/bevel.c operators/bmesh_dupeops.c operators/utils.c operators/subdivideop.c diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h index 01f714000f0..3cb938dad71 100644 --- a/source/blender/bmesh/bmesh.h +++ b/source/blender/bmesh/bmesh.h @@ -216,16 +216,23 @@ int BM_Dissolve_Vert ( BMesh *bm, BMVert *v ); /*Interpolation*/ + +/*projects target onto source for customdata interpolation. note: only + does loop customdata.*/ +void BM_face_interp_from_face(BMesh *bm, BMFace *target, BMFace *source); + +/*same as BM_face_interp_from_face, but only interpolates one loop, instead + of all loops in a face*/ +void BM_loop_interp_from_face(BMesh *bm, BMLoop *target, BMFace *source); + void BM_Data_Interp_From_Verts ( struct BMesh *bm, struct BMVert *v1, struct BMVert *v2, struct BMVert *v, float fac ); void BM_Data_Facevert_Edgeinterp ( struct BMesh *bm, struct BMVert *v1, struct BMVert *v2, struct BMVert *v, struct BMEdge *e1, float fac ); -//void bmesh_data_interp_from_face(struct BMesh *bm, struct BMFace *source, struct BMFace *target); void BM_add_data_layer ( BMesh *em, CustomData *data, int type ); void BM_add_data_layer_named ( BMesh *bm, CustomData *data, int type, char *name ); void BM_free_data_layer ( BMesh *em, CustomData *data, int type ); float BM_GetCDf(struct CustomData *cd, void *element, int type); void BM_SetCDf(struct CustomData *cd, void *element, int type, float val); - /*computes the centroid of a face, using the center of the bounding box*/ int BM_Compute_Face_Center ( BMesh *bm, BMFace *f, float center[3] ); diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c index 9dfe3c63be9..57318f8433e 100644 --- a/source/blender/bmesh/intern/bmesh_interp.c +++ b/source/blender/bmesh/intern/bmesh_interp.c @@ -39,6 +39,7 @@ #include "BKE_utildefines.h" #include "BLI_array.h" +#include "BLI_math.h" #include "bmesh.h" #include "bmesh_private.h" @@ -78,7 +79,6 @@ void BM_Data_Interp_From_Verts(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v, flo to the average of the face regions surrounding it. */ -//CustomData_bmesh_interp(&bm->ldata, src,w, NULL, 2, vloop->head.data); void BM_Data_Vert_Average(BMesh *bm, BMFace *f) { @@ -175,13 +175,91 @@ void BM_loops_to_corners(BMesh *bm, Mesh *me, int findex, } } -//static void bmesh_data_interp_from_face(BME_Mesh *bm, BMFace *source, BMFace *target) -//{ -// -//} -/*insert BM_data_interp_from_face here for mean value coordinates...*/ +/** + * BM_data_interp_from_face + * + * projects target onto source, and pulls interpolated customdata from + * source. + * + * Returns - + * Nothing +*/ +void BM_face_interp_from_face(BMesh *bm, BMFace *target, BMFace *source) +{ + BMLoop *l1, *l2; + void **blocks=NULL; + float (*cos)[3]=NULL, *w=NULL; + BLI_array_staticdeclare(cos, 64); + BLI_array_staticdeclare(w, 64); + BLI_array_staticdeclare(blocks, 64); + + BM_Copy_Attributes(bm, bm, source, target); + + l2 = bm_firstfaceloop(source); + do { + BLI_array_growone(cos); + copy_v3_v3(cos[BLI_array_count(cos)-1], l2->v->co); + BLI_array_growone(w); + BLI_array_append(blocks, l2->head.data); + l2 = l2->next; + } while (l2 != bm_firstfaceloop(source)); + + l1 = bm_firstfaceloop(target); + do { + interp_weights_poly_v3(w, cos, source->len, l1->v->co); + CustomData_bmesh_interp(&bm->ldata, blocks, w, NULL, BLI_array_count(blocks), l1->head.data); + l1 = l1->next; + } while (l1 != bm_firstfaceloop(target)); + + BLI_array_free(cos); + BLI_array_free(w); + BLI_array_free(blocks); +} + +void BM_loop_interp_from_face(BMesh *bm, BMLoop *target, BMFace *source) +{ + BMLoop *l; + void **blocks=NULL; + float (*cos)[3]=NULL, *w=NULL, cent[3] = {0.0f, 0.0f, 0.0f}; + BLI_array_staticdeclare(cos, 64); + BLI_array_staticdeclare(w, 64); + BLI_array_staticdeclare(blocks, 64); + int i; + + BM_Copy_Attributes(bm, bm, source, target->f); + + l = bm_firstfaceloop(source); + do { + BLI_array_growone(cos); + copy_v3_v3(cos[BLI_array_count(cos)-1], l->v->co); + add_v3_v3(cent, cos[BLI_array_count(cos)-1]); + + BLI_array_append(w, 0.0f); + BLI_array_append(blocks, l->head.data); + l = l->next; + } while (l != bm_firstfaceloop(source)); + + /*scale source face coordinates a bit, so points sitting directonly on an + edge will work.*/ + mul_v3_fl(cent, 1.0/source->len); + for (i=0; ilen; i++) { + float vec[3]; + sub_v3_v3v3(vec, cent, cos[i]); + mul_v3_fl(vec, 0.01); + add_v3_v3(cos[i], vec); + } + + /*interpolate*/ + interp_weights_poly_v3(w, cos, source->len, target->v->co); + CustomData_bmesh_interp(&bm->ldata, blocks, w, NULL, source->len, target->head.data); + + BLI_array_free(cos); + BLI_array_free(w); + BLI_array_free(blocks); +} + static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data) { BMIter iter; diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index 957a97b61fa..c949d730d8c 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -938,6 +938,22 @@ BMOpDefine def_create_cube = { 0, }; +/* + Bevel + + Bevels edges and vertices + */ +BMOpDefine def_bevel = { + "bevel", + {{BMOP_OPSLOT_ELEMENT_BUF, "geom"}, /* input edges and vertices */ + {BMOP_OPSLOT_ELEMENT_BUF, "face_spans"}, /* new geometry */ + {BMOP_OPSLOT_ELEMENT_BUF, "face_holes"}, /* new geometry */ + {BMOP_OPSLOT_FLT, "percent"}, /* percentage to expand bevelled edges*/ + {0} /*null-terminating sentinel*/}, + bmesh_bevel_exec, + 0 +}; + BMOpDefine *opdefines[] = { &def_splitop, &def_dupeop, @@ -997,6 +1013,7 @@ BMOpDefine *opdefines[] = { &def_create_cone, &def_create_cube, &def_join_triangles, + &def_bevel, }; int bmesh_total_ops = (sizeof(opdefines) / sizeof(void*)); diff --git a/source/blender/bmesh/intern/bmesh_operators_private.h b/source/blender/bmesh/intern/bmesh_operators_private.h index e60d40efb24..b81475d314f 100644 --- a/source/blender/bmesh/intern/bmesh_operators_private.h +++ b/source/blender/bmesh/intern/bmesh_operators_private.h @@ -68,5 +68,6 @@ void bmesh_create_uvsphere_exec(BMesh *bm, BMOperator *op); void bmesh_create_grid_exec(BMesh *bm, BMOperator *op); void bmesh_create_cube_exec(BMesh *bm, BMOperator *op); void bmesh_jointriangles_exec(BMesh *bm, BMOperator *op); +void bmesh_bevel_exec(BMesh *bm, BMOperator *op); #endif diff --git a/source/blender/bmesh/operators/bevel.c b/source/blender/bmesh/operators/bevel.c new file mode 100644 index 00000000000..315b252e843 --- /dev/null +++ b/source/blender/bmesh/operators/bevel.c @@ -0,0 +1,704 @@ +#include "MEM_guardedalloc.h" + +#include "BKE_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; + + +/* "Projects" a vector perpendicular to vec2 against vec1, such that + * the projected vec1 + vec2 has a min distance of 1 from the "edge" defined by vec2. + * note: the direction, is_forward, is used in conjunction with up_vec to determine + * whether this is a convex or concave corner. If it is a concave corner, it will + * be projected "backwards." If vec1 is before vec2, is_forward should be 0 (we are projecting backwards). + * vec1 is the vector to project onto (expected to be normalized) + * vec2 is the direction of projection (pointing away from vec1) + * up_vec is used for orientation (expected to be normalized) + * returns the length of the projected vector that lies along vec1 */ +static float BM_bevel_project_vec(float *vec1, float *vec2, float *up_vec, int is_forward) { + float factor, vec3[3], tmp[3],c1,c2; + + cross_v3_v3v3(tmp,vec1,vec2); + normalize_v3(tmp); + factor = dot_v3v3(up_vec,tmp); + if ((factor > 0 && is_forward) || (factor < 0 && !is_forward)) { + cross_v3_v3v3(vec3,vec2,tmp); /* hmm, maybe up_vec should be used instead of tmp */ + } + else { + cross_v3_v3v3(vec3,tmp,vec2); /* hmm, maybe up_vec should be used instead of tmp */ + } + normalize_v3(vec3); + c1 = dot_v3v3(vec3,vec1); + c2 = dot_v3v3(vec1,vec1); + if (fabs(c1) < 0.000001f || fabs(c2) < 0.000001f) { + factor = 0.0f; + } + else { + factor = c2/c1; + } + + return factor; +} + +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; + + 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); + + /*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) < DBL_EPSILON*10) { + copy_v3_v3(no, l->f->no); + } + + /*compute offsets*/ + l1 = len_v3(vec1)*fac; + l2 = len_v3(vec2)*fac; + if (dot_v3v3(no, l->f->no) < 0.0) { + l1 = -l1; + l2 = -l2; + } + + /*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); + } +#endif + /*oddly, this simplistic method seems to work the best*/ + mul_v3_fl(vec1, fac); + mul_v3_fl(vec2, fac); + add_v3_v3(vec1, vec2); + mul_v3_fl(vec1, 0.5); + + add_v3_v3v3(co, vec1, l->v->co); +} + +#define ETAG_SET(e, v, nv) (v) == (e)->v1 ? (etags[BMINDEX_GET((e))].newv1 = (nv)) : (etags[BMINDEX_GET((e))].newv2 = (nv)) +#define ETAG_GET(e, v) ((v) == (e)->v1 ? (etags[BMINDEX_GET((e))].newv1) : (etags[BMINDEX_GET((e))].newv2)) + +void bmesh_bevel_exec(BMesh *bm, BMOperator *op) +{ + BMOIter siter; + BMIter iter; + BMEdge *e; + BMVert *v; + BMFace **faces = NULL; + LoopTag *tags=NULL, *tag; + EdgeTag *etags = NULL, *etag; + 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; + + 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); + } + } + + 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)) { + BMINDEX_SET(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) { + BMINDEX_SET(l2, BLI_array_count(tags)); + BLI_array_growone(tags); + + if (!BMO_TestFlag(bm, l2->e, EDGE_OLD)) { + BMINDEX_SET(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 { + BMINDEX_SET(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); + //continue; + } + + if (!BLI_smallhash_haskey(&hash, (intptr_t)e)) { + BLI_array_growone(etags); + BMINDEX_SET(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); + BMINDEX_SET(l2, BLI_array_count(tags)-1); + + if (!BLI_smallhash_haskey(&hash, (intptr_t)l2->e)) { + BLI_array_growone(etags); + BMINDEX_SET(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); + 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; ie, BEVEL_FLAG)) { + if (BMO_TestFlag(bm, l->prev->e, BEVEL_FLAG)) + { + tag = tags + BMINDEX_GET(l); + calc_corner_co(bm, l, co, fac); + tag->newv = BM_Make_Vert(bm, co, l->v); + } else { + tag = tags + BMINDEX_GET(l); + tag->newv = ETAG_GET(l->prev->e, l->v); + + if (!tag->newv) { + sub_v3_v3v3(co, l->prev->v->co, l->v->co); + 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 + BMINDEX_GET(l); + tag->newv = ETAG_GET(l->e, l->v); + + if (!tag->newv) { + sub_v3_v3v3(co, l->next->v->co, l->v->co); + mul_v3_fl(co, fac); + add_v3_v3(co, l->v->co); + + tag = tags + BMINDEX_GET(l); + tag->newv = BM_Make_Vert(bm, co, l->v); + + ETAG_SET(l->e, l->v, tag->newv); + } + } else { + tag = tags + BMINDEX_GET(l); + tag->newv = l->v; + BMO_ClearFlag(bm, l->v, BEVEL_DEL); + } + } + } + + /*create new faces*/ + for (i=0; inewv); + + etag = etags + BMINDEX_GET(l->e); + v2 = l->next->v == l->e->v1 ? etag->newv1 : etag->newv2; + + tag = tags + BMINDEX_GET(l->next); + if (!BMO_TestFlag(bm, l->e, BEVEL_FLAG) && v2 && v2 != tag->newv) { + BLI_array_append(verts, v2); + } + } + + for (j=0; je, BEVEL_FLAG)) + continue; + + v1 = tags[BMINDEX_GET(l)].newv; + v2 = tags[BMINDEX_GET(l->next)].newv; + if (l->radial_next != l) { + v3 = tags[BMINDEX_GET(l->radial_next)].newv; + if (l->radial_next->next->v == l->next->v) { + v4 = v3; + v3 = tags[BMINDEX_GET(l->radial_next->next)].newv; + } else { + v4 = tags[BMINDEX_GET(l->radial_next->next)].newv; + } + } else { + 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; + + f = BM_Make_QuadTri(bm, v4, v3, v2, v1, l->f, 1); + if (!f) { + printf("eek!\n"); + 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 + BMINDEX_GET(l); + else + tag = tags + BMINDEX_GET(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= 3) { + BMFace *f; + + f = BM_Make_Ngon(bm, lastv, vstart, edges, BLI_array_count(edges), 0); + if (!f) { + printf("eek! in bevel vert fill!\n"); + } else + BMO_SetFlag(bm, f, FACE_NEW|FACE_HOLE); + } + BLI_smallhash_release(&tmphash); + } + + /*copy over customdata*/ + for (i=0; inewv) + 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) { + BM_Copy_Attributes(bm, bm, l->f, l2->f); + BM_loop_interp_from_face(bm, l2, f); + } else { + BM_Copy_Attributes(bm, bm, l->f, l2->f); + BM_Copy_Attributes(bm, bm, l, l2); + } + } + } + } + + /*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, *l3; + + BM_Copy_Attributes(bm, bm, lorig->f, l2->f); + BM_Copy_Attributes(bm, bm, lorig, l2); + } + } + } + + 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); +} diff --git a/source/blender/editors/mesh/bmesh_tools.c b/source/blender/editors/mesh/bmesh_tools.c index 7f15056d6bd..5964a91b9b7 100644 --- a/source/blender/editors/mesh/bmesh_tools.c +++ b/source/blender/editors/mesh/bmesh_tools.c @@ -4793,3 +4793,56 @@ void MESH_OT_noise(wmOperatorType *ot) RNA_def_float(ot->srna, "factor", 0.1f, -FLT_MAX, FLT_MAX, "Factor", "", 0.0f, 1.0f); } + +/*bevel! yay!!*/ +static int mesh_bevel_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh; + Material *ma; + Tex *tex; + BMVert *eve; + BMIter iter; + BMOperator bmop; + float factor= RNA_float_get(op->ptr, "percent"), fac=factor; + int i, recursion = RNA_int_get(op->ptr, "recursion"); + + if(em==NULL) return OPERATOR_CANCELLED; + + while (recursion-- > 0) { + if (!EDBM_InitOpf(em, &bmop, op, "bevel geom=%hev percent=%f", BM_SELECT, fac)) + return OPERATOR_CANCELLED; + + BMO_Exec_Op(em->bm, &bmop); + BMO_HeaderFlag_Buffer(em->bm, &bmop, "face_spans", BM_SELECT, BM_FACE); + BMO_HeaderFlag_Buffer(em->bm, &bmop, "face_holes", BM_SELECT, BM_FACE); + BMO_Finish_Op(em->bm, &bmop); + + fac = fac + (sqrt(fac) - fac)*0.25; + } + + EDBM_RecalcNormals(em); + + DAG_id_tag_update(obedit->data, 0); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_bevel(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Bevel"; + ot->description= "Edge/Vertex Bevel"; + ot->idname= "MESH_OT_bevel"; + + /* api callbacks */ + ot->exec= mesh_bevel_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_float(ot->srna, "percent", 0.16f, -FLT_MAX, FLT_MAX, "Percentage", "", -0.07f, 0.5f); + RNA_def_int(ot->srna, "recursion", 1, 1, 50, "Recursion Level", "Recursion Level", 1, 6); +} diff --git a/source/blender/editors/mesh/loopcut.c b/source/blender/editors/mesh/loopcut.c index 0c9f9d8d68d..711177e817b 100644 --- a/source/blender/editors/mesh/loopcut.c +++ b/source/blender/editors/mesh/loopcut.c @@ -247,6 +247,9 @@ static void edgering_sel(tringselOpData *lcd, int previewlines, int select) edgering_find_order(em, lasteed, startedge, lastv1, v); for(i=1;i<=previewlines;i++){ + if (!v[0][0] || !v[0][1] || !v[1][0] || !v[1][1]) + continue; + co[0][0] = (v[0][1]->co[0] - v[0][0]->co[0])*(i/((float)previewlines+1))+v[0][0]->co[0]; co[0][1] = (v[0][1]->co[1] - v[0][0]->co[1])*(i/((float)previewlines+1))+v[0][0]->co[1]; co[0][2] = (v[0][1]->co[2] - v[0][0]->co[2])*(i/((float)previewlines+1))+v[0][0]->co[2]; @@ -451,6 +454,7 @@ static int ringsel_modal (bContext *C, wmOperator *op, wmEvent *event) ringsel_exit(C, op); return OPERATOR_FINISHED; + case RETKEY: case RIGHTMOUSE: /* confirm */ // XXX hardcoded if (event->val == KM_PRESS) { /* finish */ @@ -507,6 +511,7 @@ static int loopcut_modal (bContext *C, wmOperator *op, wmEvent *event) switch (event->type) { + case RETKEY: case LEFTMOUSE: /* confirm */ // XXX hardcoded if (event->val == KM_RELEASE) { /* finish */ diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index ba5f87f47a2..aa6b586b194 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -301,6 +301,7 @@ void MESH_OT_edgering_select(struct wmOperatorType *ot); void MESH_OT_loopcut(struct wmOperatorType *ot); void MESH_OT_knifetool(struct wmOperatorType *ot); +void MESH_OT_bevel(struct wmOperatorType *ot); #endif // MESH_INTERN_H diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 519a77fa4aa..d0c9f06eb46 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -148,6 +148,8 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_select_nth); WM_operatortype_append(MESH_OT_vert_connect); WM_operatortype_append(MESH_OT_knifetool); + + WM_operatortype_append(MESH_OT_bevel); } #if 0 /* UNUSED, remove? */ diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 86957ecb86c..7e93f8999f4 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -1439,7 +1439,7 @@ static int viewselected_exec(bContext *C, wmOperator *UNUSED(op)) /* like a loca INIT_MINMAX(min, max); if (ob && ob->mode & OB_MODE_WEIGHT_PAINT) { - /* hardcoded exception, we look for the one selected armature */ + /* hardcoded exception, we look for the one selectedW armature */ /* this is weak code this way, we should make a generic active/selection callback interface once... */ Base *base; for(base=scene->base.first; base; base= base->next) { diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index a5d11d6796a..a882e8f7d92 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -1609,7 +1609,7 @@ static int select_all_exec(bContext *C, wmOperator *op) luv->flag |= MLOOPUV_VERTSEL; break; case SEL_DESELECT: - luv->flag &= MLOOPUV_VERTSEL; + luv->flag &= ~MLOOPUV_VERTSEL; break; case SEL_INVERT: luv->flag ^= MLOOPUV_VERTSEL; diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c index d5235736368..35571cd8e76 100644 --- a/source/blender/modifiers/intern/MOD_util.c +++ b/source/blender/modifiers/intern/MOD_util.c @@ -132,7 +132,7 @@ DerivedMesh *get_dm(Object *ob, struct EditMesh *em, DerivedMesh *dm, float (*ve return dm; if(ob->type==OB_MESH) { - if(em) dm= CDDM_from_editmesh(em, ob->data); + if(em) dm= CDDM_from_BMEditMesh(em, ob->data); else dm = CDDM_from_mesh((struct Mesh *)(ob->data), ob); if(vertexCos) {