Commit: 2d1e07268645b481dbbb924a5f638dc9fa870945
Author: Campbell Barton
Date:   Wed Feb 11 19:40:54 2015 +1100
Branches: master
https://developer.blender.org/rB2d1e07268645b481dbbb924a5f638dc9fa870945

UV Island support for vertex & edge slide

This ensures slide with `Correct UVs` enabled, keeps UV's (any loop 
custom-data) contiguous.

Adds 2 key functions `BM_vert_loop_groups_data_layer_create` and 
`BM_vert_loop_groups_data_layer_merge`

They work by collecting matching loop custom-data around the vertices loop-fan,
and merging the custom-data after edits are made.

Thanks to @mont29 for review!

===================================================================

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

===================================================================

diff --git a/source/blender/bmesh/intern/bmesh_interp.c 
b/source/blender/bmesh/intern/bmesh_interp.c
index a32f281..45da3ce 100644
--- a/source/blender/bmesh/intern/bmesh_interp.c
+++ b/source/blender/bmesh/intern/bmesh_interp.c
@@ -40,6 +40,8 @@
 
 #include "BKE_customdata.h"
 #include "BKE_multires.h"
+#include "BLI_memarena.h"
+#include "BLI_linklist.h"
 
 #include "bmesh.h"
 #include "intern/bmesh_private.h"
@@ -893,3 +895,179 @@ void BM_elem_float_data_set(CustomData *cd, void 
*element, int type, const float
        float *f = CustomData_bmesh_get(cd, ((BMHeader *)element)->data, type);
        if (f) *f = val;
 }
+
+/** \name Loop interpolation functions: BM_vert_loop_groups_data_layer_***
+ *
+ * Handling loop custom-data such as UV's, while keeping contiguous fans is 
rather tedious.
+ * Especially when a verts loops can have multiple CustomData layers,
+ * and each layer can have multiple (different) contiguous fans.
+ * Said differently, a single vertices loops may span multiple UV islands.
+ *
+ * These functions snapshot vertices loops, storing each contiguous fan in its 
own group.
+ * The caller can manipulate the loops, then re-combine the CustomData values.
+ *
+ * While these functions don't explicitly handle multiple layers at once,
+ * the caller can simply store its own list.
+ *
+ * \note Currently they are averaged back together (weighted by loop angle)
+ * but we could copy add other methods to re-combine CustomData-Loop-Fans.
+ *
+ * \{ */
+
+struct LoopWalkCtx {
+       /* same for all groups */
+       int type;
+       int cd_layer_offset;
+       MemArena *arena;
+
+       /* --- Per loop fan vars --- */
+
+       /* reference for this contiguous fan */
+       const void *data_ref;
+       int data_len;
+       /* both arrays the size of the 'BM_vert_face_count(v)'
+        * each contiguous fan gets a slide of these arrays */
+       void **data_array;
+       float *weight_array;
+       /* accumulate 'LoopGroupCD.weight' to make unit length */
+       float weight_accum;
+};
+
+/* Store vars to pass into 'CustomData_bmesh_interp' */
+struct LoopGroupCD {
+       /* direct customdata pointer array */
+       void **data;
+       /* weights (aligned with 'data') */
+       float *data_weights;
+       /* number of loops in the fan */
+       int data_len;
+};
+
+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->weight_array[lwc->data_len] = w;
+       lwc->weight_accum += w;
+
+       lwc->data_len += 1;
+}
+
+/**
+ * called recursively, keep stack-usage minimal.
+ *
+ * \note called for fan matching so we're pretty much safe not to break the 
stack
+ */
+static void bm_loop_walk_data(struct LoopWalkCtx *lwc, BMLoop *l_walk)
+{
+       BLI_assert(CustomData_data_equals(lwc->type, lwc->data_ref, 
BM_ELEM_CD_GET_VOID_P(l_walk, lwc->cd_layer_offset)));
+       BLI_assert(BM_elem_flag_test(l_walk, BM_ELEM_INTERNAL_TAG) == false);
+
+       bm_loop_walk_add(lwc, l_walk);
+
+#define WALK_LOOP(l_test) \
+{ \
+       BMLoop *l_other = l_test; \
+       if (l_other->v != l_walk->v) { \
+               l_other = l_other->next; \
+       } \
+       BLI_assert(l_other->v == l_walk->v); \
+       if (!BM_elem_flag_test(l_other, BM_ELEM_INTERNAL_TAG)) { \
+               if (CustomData_data_equals(lwc->type, lwc->data_ref, 
BM_ELEM_CD_GET_VOID_P(l_other, lwc->cd_layer_offset))) { \
+                       bm_loop_walk_data(lwc, l_other); \
+               } \
+       } \
+} (void)0
+
+       if (l_walk->radial_next != l_walk) {
+               WALK_LOOP(l_walk->radial_next);
+       }
+
+       if (l_walk->prev->radial_next != l_walk->prev) {
+               WALK_LOOP(l_walk->prev->radial_next);
+       }
+}
+
+LinkNode *BM_vert_loop_groups_data_layer_create(BMesh *bm, BMVert *v, int 
layer_n, MemArena *arena)
+{
+       struct LoopWalkCtx lwc;
+       LinkNode *groups = NULL;
+       BMLoop *l;
+       BMIter liter;
+       int loop_num;
+
+
+       lwc.type = bm->ldata.layers[layer_n].type;
+       lwc.cd_layer_offset = bm->ldata.layers[layer_n].offset;
+       lwc.arena = arena;
+
+       loop_num = 0;
+       BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
+               BM_elem_flag_disable(l, BM_ELEM_INTERNAL_TAG);
+               loop_num++;
+       }
+
+       lwc.data_len = 0;
+       lwc.data_array = BLI_memarena_alloc(lwc.arena, sizeof(void *) * 
loop_num);
+       lwc.weight_array = BLI_memarena_alloc(lwc.arena, sizeof(float) * 
loop_num);
+
+       BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
+               if (!BM_elem_flag_test(l, BM_ELEM_INTERNAL_TAG)) {
+                       struct LoopGroupCD *lf = BLI_memarena_alloc(lwc.arena, 
sizeof(*lf));
+                       int len_prev = lwc.data_len;
+
+                       lwc.data_ref = BM_ELEM_CD_GET_VOID_P(l, 
lwc.cd_layer_offset);
+
+                       /* assign len-last */
+                       lf->data         = &lwc.data_array[lwc.data_len];
+                       lf->data_weights = &lwc.weight_array[lwc.data_len];
+                       lwc.weight_accum = 0.0f;
+
+                       /* new group */
+                       bm_loop_walk_data(&lwc, l);
+                       lf->data_len = lwc.data_len - len_prev;
+
+                       if (LIKELY(lwc.weight_accum != 0.0f)) {
+                               mul_vn_fl(lf->data_weights, lf->data_len, 1.0f 
/ lwc.weight_accum);
+                       }
+                       else {
+                               fill_vn_fl(lf->data_weights, lf->data_len, 1.0f 
/ (float)lf->data_len);
+                       }
+
+                       BLI_linklist_prepend_arena(&groups, lf, lwc.arena);
+               }
+       }
+
+       BLI_assert(lwc.data_len == loop_num);
+
+       return groups;
+}
+
+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;
+
+       CustomData_bmesh_interp(&bm->ldata, lf->data, lf->data_weights, NULL, 
lf->data_len, data);
+
+       for (i = 0; i < lf->data_len; i++) {
+               CustomData_copy_elements(type, data, lf->data[i], 1);
+       }
+}
+
+/**
+ * Take existing custom data and merge each fan's data.
+ */
+void BM_vert_loop_groups_data_layer_merge(BMesh *bm, LinkNode *groups, int 
layer_n)
+{
+       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__single(bm, groups->link, 
data, type);
+       } 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 c605ad3..cd6d5e2 100644
--- a/source/blender/bmesh/intern/bmesh_interp.h
+++ b/source/blender/bmesh/intern/bmesh_interp.h
@@ -27,6 +27,9 @@
  *  \ingroup bmesh
  */
 
+struct LinkNode;
+struct MemArena;
+
 void  BM_loop_interp_multires(BMesh *bm, BMLoop *target, BMFace *source);
 void  BM_vert_interp_from_face(BMesh *bm, BMVert *v, BMFace *source);
 
@@ -49,5 +52,7 @@ void  BM_loop_interp_from_face(BMesh *bm, BMLoop *target, 
BMFace *source,
                                const bool do_vertex, const bool do_multires);
 
 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);
 
 #endif /* __BMESH_INTERP_H__ */
diff --git a/source/blender/editors/transform/transform.c 
b/source/blender/editors/transform/transform.c
index 92103c3..7044b75 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -50,6 +50,7 @@
 #include "BLI_listbase.h"
 #include "BLI_string.h"
 #include "BLI_ghash.h"
+#include "BLI_memarena.h"
 
 #include "BKE_nla.h"
 #include "BKE_editmesh_bvh.h"
@@ -5132,7 +5133,8 @@ static void slide_origdata_init_flag(
        if ((t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) &&
            /* don't do this at all for non-basis shape keys, too easy to
             * accidentally break uv maps or vertex colors then */
-           (bm->shapenr <= 1))
+           (bm->shapenr <= 1) &&
+           CustomData_has_math(&bm->ldata))
        {
                sod->use_origfaces = true;
        }
@@ -5155,26 +5157,89 @@ static void slide_origdata_init_data(
        }
 }
 
-static void slide_origdata_create_date(
+static void slide_origdata_create_data(
         TransInfo *t, SlideOrigData *sod,
-        BMVert **v_pt, unsigned int v_stride, unsigned int v_num)
+        TransDataGenericSlideVert *sv, unsigned int v_stride, unsigned int 
v_num)
 {
        if (sod->use_origfaces) {
                BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
                BMesh *bm = em->bm;
-
                unsigned int i;
-               for (i = 0; i < v_num; i++, v_pt = (void *)(((char *)v_pt) + 
v_stride)) {
+
+               const int *layer_math_map;
+               int layer_index_dst;
+               int layer_groups_array_size;
+               int j;
+
+               /* over alloc, only 'math' layers are indexed */
+               sod->layer_math_map = MEM_mallocN(bm->ldata.totlayer * 
sizeof(int), __func__);
+               layer_index_dst = 0;
+               for (j = 0; j < bm->ldata.totlayer; j++) {
+                       if (CustomData_layer_has_math(&bm->ldata, j)) {
+                               sod->layer_math_map[layer_index_dst++] = j;
+                       }
+               }
+               BLI_assert(layer_index_dst != 0);
+               layer_math_map = sod->layer_math_map;
+               layer_groups_array_size = layer_index_dst * sizeof(void *);
+               sod->layer_math_map_num = layer_index_dst;
+
+               sod->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, 
__func__);
+
+               for (i = 0; i < v_num; i++, sv = (void *)(((char *)sv) + 
v_stride)) {
                        BMIter fiter;
                        BMFace *f;
-                       BMVert *v = *v_pt;
 
-                       BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) {
+                       /* copy face data */
+                       BM_ITER_ELEM (f, &fiter, sv->v, BM_FACES_OF_VERT) {
                                if (!BLI_ghash_haskey(sod->origfaces, f)) {
                                        BMFace *f_copy = 
BM_face_copy(sod->bm_origfaces, bm, f, true, true);
                                        BLI_ghash_insert(sod->origfaces, f, 
f_copy);
                                }
                        }
+
+                       /* store cd_loop_groups */
+                       sv->cd_loop_groups = BLI_memarena_alloc(sod->arena, 
layer_groups_array_size);
+                       for (j = 0; j < layer_index_dst; j++) {
+                               const int layer_nr = layer_math_map[j];
+                               sv->cd_loop_groups[j] = 
BM_vert_loop_groups_data_layer_create(bm, sv->v, layer_nr, sod->arena);
+                       }
+               }
+       }
+}
+
+static void slide_origdata_interp_data(
+        TransInfo *t, SlideOrigData *sod,
+        TransDataGenericSlideVert *sv, unsigned int v_stride, unsigned int 
v_num,
+        bool is_final)
+{
+       if (sod->use_origfaces) {
+               BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+               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)) {
+                       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_cop

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to