[Bf-blender-cvs] [2d1e072] master: UV Island support for vertex & edge slide

Campbell Barton noreply at git.blender.org
Wed Feb 11 11:30:36 CET 2015


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. @@




More information about the Bf-blender-cvs mailing list