Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2015-02-11 11:40:54 +0300
committerCampbell Barton <ideasman42@gmail.com>2015-02-11 13:30:13 +0300
commit2d1e07268645b481dbbb924a5f638dc9fa870945 (patch)
treeb114d919168a89370b90a5aff7636c8339b6c879
parentf2951c23cf8d84bdb0964f53a93957f31c8b9f41 (diff)
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!
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.c178
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.h5
-rw-r--r--source/blender/editors/transform/transform.c259
-rw-r--r--source/blender/editors/transform/transform.h23
4 files changed, 288 insertions, 177 deletions
diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c
index a32f28169f6..45da3ce85bc 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 c605ad31ae7..cd6d5e2731d 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 92103c3b29f..7044b75fefd 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_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]);
+ }
}
}
}
@@ -5192,6 +5257,13 @@ static void slide_origdata_free_date(
BLI_ghash_free(sod->origfaces, NULL, NULL);
sod->origfaces = NULL;
}
+
+ if (sod->arena) {
+ BLI_memarena_free(sod->arena);
+ sod->arena = NULL;
+ }
+
+ MEM_SAFE_FREE(sod->layer_math_map);
}
}
@@ -5847,7 +5919,7 @@ static bool createEdgeSlideVerts(TransInfo *t)
bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
slide_origdata_init_data(t, &sld->orig_data);
- slide_origdata_create_date(t, &sld->orig_data, &sld->sv->v, sizeof(*sld->sv), sld->totsv);
+ slide_origdata_create_data(t, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
/*create copies of faces for customdata projection*/
sv_array = sld->sv;
@@ -5896,147 +5968,12 @@ void projectEdgeSlideData(TransInfo *t, bool is_final)
{
EdgeSlideData *sld = t->customData;
SlideOrigData *sod = &sld->orig_data;
- TransDataEdgeSlideVert *sv;
- BMEditMesh *em = sld->em;
- int i;
if (sod->use_origfaces == false) {
return;
}
- for (i = 0, sv = sld->sv; i < sld->totsv; sv++, i++) {
- BMIter fiter;
- BMLoop *l;
-
- BM_ITER_ELEM (l, &fiter, sv->v, BM_LOOPS_OF_VERT) {
- BMFace *f_copy; /* the copy of 'f' */
- BMFace *f_copy_flip; /* the copy of 'f' or detect if we need to flip to the shorter side. */
-
- f_copy = BLI_ghash_lookup(sod->origfaces, l->f);
-
- /* project onto copied projection face */
- f_copy_flip = f_copy;
-
- if (BM_elem_flag_test(l->e, BM_ELEM_SELECT) || BM_elem_flag_test(l->prev->e, BM_ELEM_SELECT)) {
- /* the loop is attached of the selected edges that are sliding */
- BMLoop *l_ed_sel = l;
-
- if (!BM_elem_flag_test(l->e, BM_ELEM_SELECT))
- l_ed_sel = l_ed_sel->prev;
-
- if (sld->perc < 0.0f) {
- if (BM_vert_in_face(sv->v_b, l_ed_sel->radial_next->f)) {
- f_copy_flip = BLI_ghash_lookup(sod->origfaces, l_ed_sel->radial_next->f);
- }
- }
- else if (sld->perc > 0.0f) {
- if (BM_vert_in_face(sv->v_a, l_ed_sel->radial_next->f)) {
- f_copy_flip = BLI_ghash_lookup(sod->origfaces, l_ed_sel->radial_next->f);
- }
- }
-
- BLI_assert(f_copy_flip != NULL);
- if (!f_copy_flip) {
- continue; /* shouldn't happen, but protection */
- }
- }
- else {
- /* the loop is attached to only one vertex and not a selected edge,
- * this means we have to find a selected edges face going in the right direction
- * to copy from else we get bad distortion see: [#31080] */
- BMIter eiter;
- BMEdge *e_sel;
-
- BLI_assert(l->v == sv->v);
- BM_ITER_ELEM (e_sel, &eiter, sv->v, BM_EDGES_OF_VERT) {
- if (BM_elem_flag_test(e_sel, BM_ELEM_SELECT)) {
- break;
- }
- }
-
- if (e_sel) {
- /* warning if the UV's are not contiguous, this will copy from the _wrong_ UVs
- * in fact whenever the face being copied is not 'f_copy' this can happen,
- * we could be a lot smarter about this but would need to deal with every UV channel or
- * add a way to mask out lauers when calling #BM_loop_interp_from_face() */
-
- /*
- * + +----------------+
- * \ | |
- * (this) l_adj| |
- * \ | |
- * \| e_sel |
- * +----------+----------------+ <- the edge we are sliding.
- * /|sv->v |
- * / | |
- * (or) l_adj| |
- * / | |
- * + +----------------+
- * (above)
- * 'other connected loops', attached to sv->v slide faces.
- *
- * NOTE: The faces connected to the edge may not have contiguous UV's
- * so step around the loops to find l_adj.
- * However if the 'other loops' are not cotiguous it will still give problems.
- *
- * A full solution to this would have to store
- * per-customdata-layer map of which loops are contiguous
- * and take this into account when interpolating.
- *
- * NOTE: If l_adj's edge isnt manifold then use then
- * interpolate the loop from its own face.
- * Can happen when 'other connected loops' are disconnected from the face-fan.
- */
-
- BMLoop *l_adj = NULL;
- if (sld->perc < 0.0f) {
- if (BM_vert_in_face(sv->v_b, e_sel->l->f)) {
- l_adj = e_sel->l;
- }
- else if (BM_vert_in_face(sv->v_b, e_sel->l->radial_next->f)) {
- l_adj = e_sel->l->radial_next;
- }
- }
- else if (sld->perc > 0.0f) {
- if (BM_vert_in_face(sv->v_a, e_sel->l->f)) {
- l_adj = e_sel->l;
- }
- else if (BM_vert_in_face(sv->v_a, e_sel->l->radial_next->f)) {
- l_adj = e_sel->l->radial_next;
- }
- }
-
- /* step across to the face */
- if (l_adj) {
- l_adj = BM_loop_other_edge_loop(l_adj, sv->v);
- if (!BM_edge_is_boundary(l_adj->e)) {
- l_adj = l_adj->radial_next;
- }
- else {
- /* disconnected face-fan, fallback to self */
- l_adj = l;
- }
-
- f_copy_flip = BLI_ghash_lookup(sod->origfaces, l_adj->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_flip, false, false);
-
- if (is_final) {
- BM_loop_interp_multires(em->bm, l, f_copy_flip);
- if (f_copy != f_copy_flip) {
- BM_loop_interp_multires(em->bm, l, f_copy);
- }
- }
-
- /* make sure face-attributes are correct (e.g. MTexPoly) */
- BM_elem_attrs_copy(sod->bm_origfaces, em->bm, f_copy, l->f);
- }
- }
+ slide_origdata_interp_data(t, sod, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv, is_final);
}
void freeEdgeSlideTempFaces(EdgeSlideData *sld)
@@ -6544,7 +6481,7 @@ static bool createVertSlideVerts(TransInfo *t)
bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
slide_origdata_init_data(t, &sld->orig_data);
- slide_origdata_create_date(t, &sld->orig_data, &sld->sv->v, sizeof(*sld->sv), sld->totsv);
+ slide_origdata_create_data(t, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
sld->em = em;
@@ -6564,42 +6501,12 @@ void projectVertSlideData(TransInfo *t, bool is_final)
{
VertSlideData *sld = t->customData;
SlideOrigData *sod = &sld->orig_data;
- TransDataVertSlideVert *sv;
- BMEditMesh *em = sld->em;
- int i;
if (sod->use_origfaces == false) {
return;
}
- for (i = 0, sv = sld->sv; i < sld->totsv; sv++, i++) {
- BMIter fiter;
- BMLoop *l;
-
- BM_ITER_ELEM (l, &fiter, sv->v, BM_LOOPS_OF_VERT) {
- BMFace *f_copy; /* the copy of 'f' */
- BMFace *f_copy_flip; /* the copy of 'f' or detect if we need to flip to the shorter side. */
-
- f_copy = BLI_ghash_lookup(sod->origfaces, l->f);
-
- /* project onto copied projection face */
- f_copy_flip = f_copy;
-
- /* 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_flip, false, false);
-
- if (is_final) {
- BM_loop_interp_multires(em->bm, l, f_copy_flip);
- if (f_copy != f_copy_flip) {
- BM_loop_interp_multires(em->bm, l, f_copy);
- }
- }
-
- /* make sure face-attributes are correct (e.g. MTexPoly) */
- BM_elem_attrs_copy(sod->bm_origfaces, em->bm, f_copy, l->f);
- }
- }
+ slide_origdata_interp_data(t, sod, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv, is_final);
}
void freeVertSlideTempFaces(VertSlideData *sld)
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 2330ec6e79e..84a81e8b3d8 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -200,9 +200,19 @@ typedef struct TransDataNla {
struct LinkNode;
struct GHash;
+/* header of TransDataEdgeSlideVert, TransDataEdgeSlideEdge */
+typedef struct TransDataGenericSlideVert {
+ struct BMVert *v;
+ struct LinkNode **cd_loop_groups;
+} TransDataGenericSlideVert;
+
typedef struct TransDataEdgeSlideVert {
- struct BMVert *v_a, *v_b;
+ /* TransDataGenericSlideVert */
struct BMVert *v;
+ struct LinkNode **cd_loop_groups;
+ /* end generic */
+
+ struct BMVert *v_a, *v_b;
float v_co_orig[3];
float edge_len;
@@ -220,6 +230,13 @@ typedef struct SlideOrigData {
bool use_origfaces;
struct GHash *origfaces;
struct BMesh *bm_origfaces;
+
+ struct MemArena *arena;
+ /* number of math BMLoop layers */
+ int layer_math_map_num;
+ /* array size of 'layer_math_map_num'
+ * maps TransDataVertSlideVert.cd_group index to absolute CustomData layer index */
+ int *layer_math_map;
} SlideOrigData;
typedef struct EdgeSlideData {
@@ -241,7 +258,11 @@ typedef struct EdgeSlideData {
typedef struct TransDataVertSlideVert {
+ /* TransDataGenericSlideVert */
BMVert *v;
+ struct LinkNode **cd_loop_groups;
+ /* end generic */
+
float co_orig_3d[3];
float co_orig_2d[2];
float (*co_link_orig_3d)[3];