Vert/Edge Slide: better UV interpolation
authorCampbell Barton <ideasman42@gmail.com>
Mon, 16 Feb 2015 07:49:18 +0000 (18:49 +1100)
committerCampbell Barton <ideasman42@gmail.com>
Mon, 16 Feb 2015 07:49:18 +0000 (18:49 +1100)
Ignore faces which the sliding vert is outside of.

source/blender/bmesh/intern/bmesh_interp.c
source/blender/bmesh/intern/bmesh_interp.h
source/blender/editors/transform/transform.c
source/blender/editors/transform/transform.h

index a88f38caf7821910153b8e5a2c27b7b28c006bf2..d60c01bd0ff994c9c9665ada781c1124990f76c9 100644 (file)
@@ -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
index cd6d5e2731d86d4e785e36cac26260eeef590074..1c1c063b7ed18cd542d3bd93e5921834d56800b4 100644 (file)
@@ -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__ */
index 1740e54abbf6611fb14bd4e5d3db3b16c0aa9213..193bcbb369105d8b637f6a13b80fa7c9d9695c06 100644 (file)
@@ -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;
index 84a81e8b3d82406c437617998fcaa75ef0af61bb..8d6c693b14a1a4069069869e824096825da00902 100644 (file)
@@ -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];