diff options
-rw-r--r-- | source/blender/bmesh/intern/bmesh_interp.c | 36 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_interp.h | 2 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_opdefines.c | 1 | ||||
-rw-r--r-- | source/blender/bmesh/operators/bmo_inset.c | 118 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_inset.c | 6 |
5 files changed, 146 insertions, 17 deletions
diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c index 120618a90e2..b6585811fd5 100644 --- a/source/blender/bmesh/intern/bmesh_interp.c +++ b/source/blender/bmesh/intern/bmesh_interp.c @@ -167,6 +167,29 @@ void BM_data_interp_face_vert_edge(BMesh *bm, BMVert *v1, BMVert *UNUSED(v2), BM * * \note Only handles loop customdata. multires is handled. */ +void BM_face_interp_from_face_ex(BMesh *bm, BMFace *target, BMFace *source, + void **blocks, float (*cos_2d)[2], float axis_mat[3][3]) +{ + BMLoop *l_iter; + BMLoop *l_first; + + float *w = BLI_array_alloca(w, source->len); + float co[2]; + int i; + + if (source != target) + BM_elem_attrs_copy(bm, bm, source, target); + + /* interpolate */ + i = 0; + l_iter = l_first = BM_FACE_FIRST_LOOP(target); + do { + mul_v2_m3v3(co, axis_mat, l_iter->v->co); + interp_weights_poly_v2(w, cos_2d, source->len, co); + CustomData_bmesh_interp(&bm->ldata, blocks, w, NULL, source->len, l_iter->head.data); + } while (i++, (l_iter = l_iter->next) != l_first); +} + void BM_face_interp_from_face(BMesh *bm, BMFace *target, BMFace *source) { BMLoop *l_iter; @@ -176,14 +199,11 @@ void BM_face_interp_from_face(BMesh *bm, BMFace *target, BMFace *source) float (*cos_2d)[2] = BLI_array_alloca(cos_2d, source->len); float *w = BLI_array_alloca(w, source->len); float axis_mat[3][3]; /* use normal to transform into 2d xy coords */ - float co[2]; int i; /* convert the 3d coords into 2d for projection */ axis_dominant_v3_to_m3(axis_mat, source->no); - BM_elem_attrs_copy(bm, bm, source, target); - i = 0; l_iter = l_first = BM_FACE_FIRST_LOOP(source); do { @@ -191,14 +211,8 @@ void BM_face_interp_from_face(BMesh *bm, BMFace *target, BMFace *source) blocks[i] = l_iter->head.data; } while (i++, (l_iter = l_iter->next) != l_first); - /* interpolate */ - i = 0; - l_iter = l_first = BM_FACE_FIRST_LOOP(target); - do { - mul_v2_m3v3(co, axis_mat, l_iter->v->co); - interp_weights_poly_v2(w, cos_2d, source->len, co); - CustomData_bmesh_interp(&bm->ldata, blocks, w, NULL, source->len, l_iter->head.data); - } while (i++, (l_iter = l_iter->next) != l_first); + BM_face_interp_from_face_ex(bm, target, source, + blocks, cos_2d, axis_mat); } /** diff --git a/source/blender/bmesh/intern/bmesh_interp.h b/source/blender/bmesh/intern/bmesh_interp.h index 3563ed1f40e..1a1ca241224 100644 --- a/source/blender/bmesh/intern/bmesh_interp.h +++ b/source/blender/bmesh/intern/bmesh_interp.h @@ -42,6 +42,8 @@ void BM_data_layer_copy(BMesh *bm, CustomData *data, int type, int src_n, int d float BM_elem_float_data_get(CustomData *cd, void *element, int type); void BM_elem_float_data_set(CustomData *cd, void *element, int type, const float val); +void BM_face_interp_from_face_ex(BMesh *bm, BMFace *target, BMFace *source, + void **blocks, float (*cos_2d)[2], float axis_mat[3][3]); void BM_face_interp_from_face(BMesh *bm, BMFace *target, BMFace *source); void BM_loop_interp_from_face(BMesh *bm, BMLoop *target, BMFace *source, const bool do_vertex, const bool do_multires); diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index 41e18756559..9006f3893a2 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -1533,6 +1533,7 @@ static BMOpDefine bmo_inset_region_def = { {{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces */ {"use_boundary", BMO_OP_SLOT_BOOL}, {"use_even_offset", BMO_OP_SLOT_BOOL}, + {"use_interpolate", BMO_OP_SLOT_BOOL}, {"use_relative_offset", BMO_OP_SLOT_BOOL}, {"thickness", BMO_OP_SLOT_FLT}, {"depth", BMO_OP_SLOT_FLT}, diff --git a/source/blender/bmesh/operators/bmo_inset.c b/source/blender/bmesh/operators/bmo_inset.c index 26574aaf57d..d58894d7a1c 100644 --- a/source/blender/bmesh/operators/bmo_inset.c +++ b/source/blender/bmesh/operators/bmo_inset.c @@ -32,6 +32,8 @@ #include "BLI_math.h" #include "BLI_array.h" +#include "BLI_memarena.h" +#include "BKE_customdata.h" #include "bmesh.h" @@ -243,6 +245,59 @@ typedef struct SplitEdgeInfo { BMLoop *l; } SplitEdgeInfo; + +/** + * Interpolation, this is more complex for regions since we're not creating new faces + * and throwing away old ones, so instead, store face data needed for interpolation. + * + * \note This uses CustomData functions in quite a low-level way which should be + * avoided, but in this case its hard to do without storing a duplicate mesh. */ + +/* just enough of a face to store interpolation data we can use once the inset is done */ +typedef struct InterpFace { + BMFace *f; + void **blocks; + float (*cos_2d)[2]; + float axis_mat[3][3]; +} InterpFace; + +/* basically a clone of #BM_vert_interp_from_face */ +static void bm_interp_face_store(InterpFace *iface, BMesh *bm, BMFace *f, MemArena *interp_arena) +{ + BMLoop *l_iter, *l_first; + void **blocks = iface->blocks = BLI_memarena_alloc(interp_arena, sizeof(*iface->blocks) * f->len); + float (*cos_2d)[2] = iface->cos_2d = BLI_memarena_alloc(interp_arena, sizeof(*iface->cos_2d) * f->len); + void *axis_mat = iface->axis_mat; + int i; + + axis_dominant_v3_to_m3(axis_mat, f->no); + + iface->f = f; + + i = 0; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + mul_v2_m3v3(cos_2d[i], axis_mat, l_iter->v->co); + blocks[i] = NULL; + CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, l_iter->head.data, &blocks[i]); + /* if we were not modifying the loops later we would do... */ + // blocks[i] = l_iter->head.data; + + /* use later for index lookups */ + BM_elem_index_set(l_iter, i); /* set_ok */ + } while (i++, (l_iter = l_iter->next) != l_first); +} +static void bm_interp_face_free(InterpFace *iface, BMesh *bm) +{ + void **blocks = iface->blocks; + int i; + + for (i = 0; i < iface->f->len; i++) { + CustomData_bmesh_free_block(&bm->ldata, &blocks[i]); + } +} + + /** * return the tag loop where there is... * - only 1 tagged face attached to this edge. @@ -298,6 +353,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op) const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset"); const bool use_even_boundry = use_even_offset; /* could make own option */ const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset"); + const bool use_interpolate = BMO_slot_bool_get(op->slots_in, "use_interpolate"); const float thickness = BMO_slot_float_get(op->slots_in, "thickness"); const float depth = BMO_slot_float_get(op->slots_in, "depth"); @@ -307,11 +363,24 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op) SplitEdgeInfo *edge_info; SplitEdgeInfo *es; + /* Interpolation Vars */ + /* an array alligned with faces but only fill items which are used. */ + InterpFace **iface_array = NULL; + int iface_array_len; + MemArena *interp_arena = NULL; + BMVert *v; BMEdge *e; BMFace *f; int i, j, k; + if (use_interpolate) { + interp_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + /* warning, we could be more clever here and not over alloc */ + iface_array = MEM_callocN(sizeof(*iface_array) * bm->totface, __func__); + iface_array_len = bm->totface; + } + if (use_outset == false) { BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); BMO_slot_buffer_hflag_enable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false); @@ -392,9 +461,22 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op) /* important to tag again here */ BM_elem_flag_enable(es->e_new->v1, BM_ELEM_TAG); BM_elem_flag_enable(es->e_new->v2, BM_ELEM_TAG); - } + /* initialize interpolation vars */ + /* this could go in its own loop, + * only use the 'es->l->f' so we don't store loops for faces which have no mixed selection */ + if (use_interpolate) { + const int j = BM_elem_index_get((f = es->l->f)); + if (iface_array[j] == NULL) { + InterpFace *iface = BLI_memarena_alloc(interp_arena, sizeof(*iface)); + bm_interp_face_store(iface, bm, f, interp_arena); + iface_array[j] = iface; + } + } + /* done interpolation */ + } + /* show edge normals for debugging */ #if 0 for (i = 0, es = edge_info; i < edge_info_len; i++, es++) { @@ -638,6 +720,16 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op) } } + if (use_interpolate) { + for (i = 0; i < iface_array_len; i++) { + if (iface_array[i]) { + InterpFace *iface = iface_array[i]; + BM_face_interp_from_face_ex(bm, iface->f, iface->f, + iface->blocks, iface->cos_2d, iface->axis_mat); + } + } + } + /* create faces */ for (i = 0, es = edge_info; i < edge_info_len; i++, es++) { BMVert *varr[4] = {NULL}; @@ -704,10 +796,30 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op) l_b = l_a->next; /* swap a<->b intentionally */ - BM_elem_attrs_copy(bm, bm, l_a_other, l_b); - BM_elem_attrs_copy(bm, bm, l_b_other, l_a); + if (use_interpolate) { + InterpFace *iface = iface_array[BM_elem_index_get(es->l->f)]; + const int i_a = BM_elem_index_get(l_a_other); + const int i_b = BM_elem_index_get(l_b_other); + CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, iface->blocks[i_a], &l_b->head.data); + CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, iface->blocks[i_b], &l_a->head.data); + } + else { + BM_elem_attrs_copy(bm, bm, l_a_other, l_b); + BM_elem_attrs_copy(bm, bm, l_b_other, l_a); + } } + } #endif + + if (use_interpolate) { + for (i = 0; i < iface_array_len; i++) { + if (iface_array[i]) { + bm_interp_face_free(iface_array[i], bm); + } + } + + BLI_memarena_free(interp_arena); + MEM_freeN(iface_array); } /* we could flag new edges/verts too, is it useful? */ diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c index c9a96018e2a..7a879d398f1 100644 --- a/source/blender/editors/mesh/editmesh_inset.c +++ b/source/blender/editors/mesh/editmesh_inset.c @@ -209,9 +209,9 @@ static int edbm_inset_calc(wmOperator *op) } else { EDBM_op_init(em, &bmop, op, - "inset_region faces=%hf use_boundary=%b use_even_offset=%b use_relative_offset=%b " - "thickness=%f depth=%f use_outset=%b", - BM_ELEM_SELECT, use_boundary, use_even_offset, use_relative_offset, + "inset_region faces=%hf use_boundary=%b use_even_offset=%b use_relative_offset=%b" + " use_interpolate=%b thickness=%f depth=%f use_outset=%b", + BM_ELEM_SELECT, use_boundary, use_even_offset, use_relative_offset, use_interpolate, thickness, depth, use_outset); } BMO_op_exec(em->bm, &bmop); |