From 58652301dee685f67edf03c2bfcfbafe15a7cb6e Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 16 Feb 2015 18:49:18 +1100 Subject: Vert/Edge Slide: better UV interpolation Ignore faces which the sliding vert is outside of. --- source/blender/bmesh/intern/bmesh_interp.c | 69 +++++++++++++++++++-- source/blender/bmesh/intern/bmesh_interp.h | 1 + source/blender/editors/transform/transform.c | 90 +++++++++++++++++++++------- source/blender/editors/transform/transform.h | 10 ++-- 4 files changed, 140 insertions(+), 30 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c index a88f38caf78..d60c01bd0ff 100644 --- a/source/blender/bmesh/intern/bmesh_interp.c +++ b/source/blender/bmesh/intern/bmesh_interp.c @@ -925,12 +925,15 @@ struct LoopWalkCtx { /* reference for this contiguous fan */ const void *data_ref; int data_len; + + /* accumulate 'LoopGroupCD.weight' to make unit length */ + float weight_accum; + /* both arrays the size of the 'BM_vert_face_count(v)' * each contiguous fan gets a slide of these arrays */ void **data_array; + int *data_index_array; float *weight_array; - /* accumulate 'LoopGroupCD.weight' to make unit length */ - float weight_accum; }; /* Store vars to pass into 'CustomData_bmesh_interp' */ @@ -939,6 +942,8 @@ struct LoopGroupCD { void **data; /* weights (aligned with 'data') */ float *data_weights; + /* index-in-face */ + int *data_index; /* number of loops in the fan */ int data_len; }; @@ -948,6 +953,7 @@ static void bm_loop_walk_add(struct LoopWalkCtx *lwc, BMLoop *l) const float w = BM_loop_calc_face_angle(l); BM_elem_flag_enable(l, BM_ELEM_INTERNAL_TAG); lwc->data_array[lwc->data_len] = BM_ELEM_CD_GET_VOID_P(l, lwc->cd_layer_offset); + lwc->data_index_array[lwc->data_len] = BM_elem_index_get(l); lwc->weight_array[lwc->data_len] = w; lwc->weight_accum += w; @@ -1001,11 +1007,14 @@ LinkNode *BM_vert_loop_groups_data_layer_create(BMesh *bm, BMVert *v, int layer_ loop_num = 0; BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { BM_elem_flag_disable(l, BM_ELEM_INTERNAL_TAG); + BM_elem_index_set(l, loop_num); /* set_dirty! */ loop_num++; } + bm->elem_index_dirty |= BM_LOOP; lwc.data_len = 0; lwc.data_array = BLI_memarena_alloc(lwc.arena, sizeof(void *) * loop_num); + lwc.data_index_array = BLI_memarena_alloc(lwc.arena, sizeof(int) * loop_num); lwc.weight_array = BLI_memarena_alloc(lwc.arena, sizeof(float) * loop_num); BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { @@ -1017,6 +1026,7 @@ LinkNode *BM_vert_loop_groups_data_layer_create(BMesh *bm, BMVert *v, int layer_ /* assign len-last */ lf->data = &lwc.data_array[lwc.data_len]; + lf->data_index = &lwc.data_index_array[lwc.data_len]; lf->data_weights = &lwc.weight_array[lwc.data_len]; lwc.weight_accum = 0.0f; @@ -1040,12 +1050,48 @@ LinkNode *BM_vert_loop_groups_data_layer_create(BMesh *bm, BMVert *v, int layer_ return groups; } -static void bm_vert_loop_groups_data_layer_merge__single(BMesh *bm, void *lf_p, void *data, int type) +static void bm_vert_loop_groups_data_layer_merge__single( + BMesh *bm, void *lf_p, void *data, int type) +{ + struct LoopGroupCD *lf = lf_p; + int i; + const float *data_weights; + + data_weights = lf->data_weights; + + CustomData_bmesh_interp(&bm->ldata, lf->data, data_weights, NULL, lf->data_len, data); + + for (i = 0; i < lf->data_len; i++) { + CustomData_copy_elements(type, data, lf->data[i], 1); + } +} + +static void bm_vert_loop_groups_data_layer_merge_weights__single( + BMesh *bm, void *lf_p, void *data, int type, const float *loop_weights) { struct LoopGroupCD *lf = lf_p; int i; + const float *data_weights; + + /* re-weight */ + float *temp_weights = BLI_array_alloca(temp_weights, lf->data_len); + float weight_accum = 0.0f; - CustomData_bmesh_interp(&bm->ldata, lf->data, lf->data_weights, NULL, lf->data_len, data); + for (i = 0; i < lf->data_len; i++) { + float w = loop_weights[lf->data_index[i]] * lf->data_weights[i]; + temp_weights[i] = w; + weight_accum += w; + } + + if (LIKELY(weight_accum != 0.0f)) { + mul_vn_fl(temp_weights, lf->data_len, 1.0f / weight_accum); + data_weights = temp_weights; + } + else { + data_weights = lf->data_weights; + } + + CustomData_bmesh_interp(&bm->ldata, lf->data, data_weights, NULL, lf->data_len, data); for (i = 0; i < lf->data_len; i++) { CustomData_copy_elements(type, data, lf->data[i], 1); @@ -1066,4 +1112,19 @@ void BM_vert_loop_groups_data_layer_merge(BMesh *bm, LinkNode *groups, int layer } while ((groups = groups->next)); } +/** + * A version of #BM_vert_loop_groups_data_layer_merge + * that takes an array of loop-weights (aligned with #BM_LOOPS_OF_VERT iterator) + */ +void BM_vert_loop_groups_data_layer_merge_weights(BMesh *bm, LinkNode *groups, int layer_n, const float *loop_weights) +{ + int type = bm->ldata.layers[layer_n].type; + int size = CustomData_sizeof(type); + void *data = alloca(size); + + do { + bm_vert_loop_groups_data_layer_merge_weights__single(bm, groups->link, data, type, loop_weights); + } while ((groups = groups->next)); +} + /** \} */ \ No newline at end of file diff --git a/source/blender/bmesh/intern/bmesh_interp.h b/source/blender/bmesh/intern/bmesh_interp.h index cd6d5e2731d..1c1c063b7ed 100644 --- a/source/blender/bmesh/intern/bmesh_interp.h +++ b/source/blender/bmesh/intern/bmesh_interp.h @@ -54,5 +54,6 @@ void BM_loop_interp_from_face(BMesh *bm, BMLoop *target, BMFace *source, void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f); struct LinkNode *BM_vert_loop_groups_data_layer_create(BMesh *bm, BMVert *v, int layer_n, struct MemArena *arena); void BM_vert_loop_groups_data_layer_merge(BMesh *bm, struct LinkNode *groups, int layer_n); +void BM_vert_loop_groups_data_layer_merge_weights(BMesh *bm, struct LinkNode *groups, int layer_n, const float *loop_weights); #endif /* __BMESH_INTERP_H__ */ diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 1740e54abbf..193bcbb3691 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -44,6 +44,7 @@ #include "DNA_movieclip_types.h" #include "DNA_scene_types.h" /* PET modes */ +#include "BLI_alloca.h" #include "BLI_utildefines.h" #include "BLI_math.h" #include "BLI_rect.h" @@ -5269,6 +5270,8 @@ static void slide_origdata_create_data( sod->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + sod->origverts = BLI_ghash_ptr_new_ex(__func__, v_num); + for (i = 0; i < v_num; i++, sv = (void *)(((char *)sv) + v_stride)) { BMIter fiter; BMFace *f; @@ -5294,6 +5297,64 @@ static void slide_origdata_create_data( else { sv->cd_loop_groups = NULL; } + + BLI_ghash_insert(sod->origverts, sv->v, sv); + } + } +} + +/** + * If we're sliding the vert, return its original location, if not, the current location is good. + */ +static const float *slide_origdata_orig_vert_co(SlideOrigData *sod, BMVert *v) +{ + TransDataGenericSlideVert *sv = BLI_ghash_lookup(sod->origverts, v); + return sv ? sv->co_orig_3d : v->co; +} + +static void slide_origdata_interp_data_vert( + SlideOrigData *sod, BMesh *bm, bool is_final, + TransDataGenericSlideVert *sv) +{ + BMIter liter; + BMLoop *l; + int j; + float *loop_weights; + const bool do_loop_weight = (len_squared_v3v3(sv->v->co, sv->co_orig_3d) > FLT_EPSILON); + + // BM_ITER_ELEM (l, &liter, sv->v, BM_LOOPS_OF_VERT) { + l = BM_iter_new(&liter, bm, BM_LOOPS_OF_VERT, sv->v); + loop_weights = do_loop_weight ? BLI_array_alloca(loop_weights, liter.count) : NULL; + for (j = 0 ; l; l = BM_iter_step(&liter), j++) { + BMFace *f_copy; /* the copy of 'f' */ + + f_copy = BLI_ghash_lookup(sod->origfaces, l->f); + + /* only loop data, no vertex data since that contains shape keys, + * and we do not want to mess up other shape keys */ + BM_loop_interp_from_face(bm, l, f_copy, false, is_final); + + /* make sure face-attributes are correct (e.g. MTexPoly) */ + BM_elem_attrs_copy(sod->bm_origfaces, bm, f_copy, l->f); + + /* weight the loop */ + if (do_loop_weight) { + const float *v_prev = slide_origdata_orig_vert_co(sod, l->prev->v); + const float *v_next = slide_origdata_orig_vert_co(sod, l->next->v); + const float dist = dist_signed_squared_to_corner_v3v3v3(sv->v->co, v_prev, sv->co_orig_3d, v_next, f_copy->no); + const float eps = 0.00001f; + loop_weights[j] = (dist >= 0.0f) ? 1.0f : ((dist <= -eps) ? 0.0f : (1.0f + (dist / eps))); + } + } + + if (do_loop_weight) { + for (j = 0; j < sod->layer_math_map_num; j++) { + BM_vert_loop_groups_data_layer_merge_weights(bm, sv->cd_loop_groups[j], sod->layer_math_map[j], loop_weights); + } + } + else { + for (j = 0; j < sod->layer_math_map_num; j++) { + BM_vert_loop_groups_data_layer_merge(bm, sv->cd_loop_groups[j], sod->layer_math_map[j]); } } } @@ -5305,33 +5366,13 @@ static void slide_origdata_interp_data( { if (sod->use_origfaces) { BMEditMesh *em = BKE_editmesh_from_object(t->obedit); + BMesh *bm = em->bm; unsigned int i; - const int *layer_math_map = sod->layer_math_map; - for (i = 0; i < v_num; i++, sv = (void *)(((char *)sv) + v_stride)) { if (sv->cd_loop_groups) { - BMIter fiter; - BMLoop *l; - int j; - - BM_ITER_ELEM (l, &fiter, sv->v, BM_LOOPS_OF_VERT) { - BMFace *f_copy; /* the copy of 'f' */ - - f_copy = BLI_ghash_lookup(sod->origfaces, l->f); - - /* only loop data, no vertex data since that contains shape keys, - * and we do not want to mess up other shape keys */ - BM_loop_interp_from_face(em->bm, l, f_copy, false, is_final); - - /* make sure face-attributes are correct (e.g. MTexPoly) */ - BM_elem_attrs_copy(sod->bm_origfaces, em->bm, f_copy, l->f); - } - - for (j = 0; j < sod->layer_math_map_num; j++) { - BM_vert_loop_groups_data_layer_merge(em->bm, sv->cd_loop_groups[j], layer_math_map[j]); - } + slide_origdata_interp_data_vert(sod, bm, is_final, sv); } } } @@ -5351,6 +5392,11 @@ static void slide_origdata_free_date( sod->origfaces = NULL; } + if (sod->origverts) { + BLI_ghash_free(sod->origverts, NULL, NULL); + sod->origverts = NULL; + } + if (sod->arena) { BLI_memarena_free(sod->arena); sod->arena = NULL; diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 84a81e8b3d8..8d6c693b14a 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -204,19 +204,20 @@ struct GHash; typedef struct TransDataGenericSlideVert { struct BMVert *v; struct LinkNode **cd_loop_groups; + float co_orig_3d[3]; } TransDataGenericSlideVert; typedef struct TransDataEdgeSlideVert { /* TransDataGenericSlideVert */ struct BMVert *v; struct LinkNode **cd_loop_groups; - /* end generic */ - - struct BMVert *v_a, *v_b; float v_co_orig[3]; + /* end generic */ float edge_len; + struct BMVert *v_a, *v_b; + /* add origvert.co to get the original locations */ float dir_a[3], dir_b[3]; @@ -228,6 +229,7 @@ typedef struct TransDataEdgeSlideVert { typedef struct SlideOrigData { /* flag that is set when origfaces is initialized */ bool use_origfaces; + struct GHash *origverts; /* map {BMVert: TransDataGenericSlideVert} */ struct GHash *origfaces; struct BMesh *bm_origfaces; @@ -261,9 +263,9 @@ typedef struct TransDataVertSlideVert { /* TransDataGenericSlideVert */ BMVert *v; struct LinkNode **cd_loop_groups; + float co_orig_3d[3]; /* end generic */ - float co_orig_3d[3]; float co_orig_2d[2]; float (*co_link_orig_3d)[3]; float (*co_link_orig_2d)[2]; -- cgit v1.2.3