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:
Diffstat (limited to 'source/blender/bmesh/intern/bmesh_mesh.c')
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c438
1 files changed, 368 insertions, 70 deletions
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index b16ea42304a..115330cb25a 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -34,10 +34,12 @@
#include "BLI_linklist_stack.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLI_stack.h"
#include "BLI_utildefines.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_editmesh.h"
+#include "BKE_mesh.h"
#include "BKE_multires.h"
#include "intern/bmesh_private.h"
@@ -301,8 +303,9 @@ static void bm_mesh_edges_calc_vectors(BMesh *bm, float (*edgevec)[3], const flo
bm->elem_index_dirty &= ~BM_EDGE;
}
-static void bm_mesh_verts_calc_normals(BMesh *bm, const float (*edgevec)[3], const float (*fnos)[3],
- const float (*vcos)[3], float (*vnos)[3])
+static void bm_mesh_verts_calc_normals(
+ BMesh *bm, const float (*edgevec)[3], const float (*fnos)[3],
+ const float (*vcos)[3], float (*vnos)[3])
{
BM_mesh_elem_index_ensure(bm, (vnos) ? (BM_EDGE | BM_VERT) : BM_EDGE);
@@ -435,10 +438,12 @@ void BM_verts_calc_normal_vcos(BMesh *bm, const float (*fnos)[3], const float (*
/**
* Helpers for #BM_mesh_loop_normals_update and #BM_loops_calc_normals_vnos
*/
-static void bm_mesh_edges_sharp_tag(BMesh *bm, const float (*vnos)[3], const float (*fnos)[3], float split_angle,
- float (*r_lnos)[3])
+static void bm_mesh_edges_sharp_tag(
+ BMesh *bm, const float (*vnos)[3], const float (*fnos)[3], float split_angle,
+ float (*r_lnos)[3])
{
- BMIter eiter;
+ BMIter eiter, viter;
+ BMVert *v;
BMEdge *e;
int i;
@@ -450,15 +455,18 @@ static void bm_mesh_edges_sharp_tag(BMesh *bm, const float (*vnos)[3], const flo
{
char htype = BM_LOOP;
- if (vnos) {
- htype |= BM_VERT;
- }
if (fnos) {
htype |= BM_FACE;
}
BM_mesh_elem_index_ensure(bm, htype);
}
+ /* Clear all vertices' tags (means they are all smooth for now). */
+ BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
+ BM_elem_index_set(v, i); /* set_inline */
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+ }
+
/* This first loop checks which edges are actually smooth, and pre-populate lnos with vnos (as if they were
* all smooth).
*/
@@ -481,13 +489,13 @@ static void bm_mesh_edges_sharp_tag(BMesh *bm, const float (*vnos)[3], const flo
* If the angle between both its polys' normals is below split_angle value,
* and it is tagged as such,
* and both its faces are smooth,
- * and both its faces have compatible (non-flipped) normals, i.e. both loops on the same edge do not share
- * the same vertex.
+ * and both its faces have compatible (non-flipped) normals,
+ * i.e. both loops on the same edge do not share the same vertex.
*/
if (is_angle_smooth &&
- BM_elem_flag_test_bool(e, BM_ELEM_SMOOTH) &&
- BM_elem_flag_test_bool(l_a->f, BM_ELEM_SMOOTH) &&
- BM_elem_flag_test_bool(l_b->f, BM_ELEM_SMOOTH) &&
+ BM_elem_flag_test(e, BM_ELEM_SMOOTH) &&
+ BM_elem_flag_test(l_a->f, BM_ELEM_SMOOTH) &&
+ BM_elem_flag_test(l_b->f, BM_ELEM_SMOOTH) &&
l_a->v != l_b->v)
{
const float *no;
@@ -499,20 +507,40 @@ static void bm_mesh_edges_sharp_tag(BMesh *bm, const float (*vnos)[3], const flo
no = vnos ? vnos[BM_elem_index_get(l_b->v)] : l_b->v->no;
copy_v3_v3(r_lnos[BM_elem_index_get(l_b)], no);
}
+ else {
+ /* Sharp edge, tag its verts as such. */
+ BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
+ BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
+ }
+ }
+ else {
+ /* Sharp edge, tag its verts as such. */
+ BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
+ BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
}
}
- bm->elem_index_dirty &= ~BM_EDGE;
+ bm->elem_index_dirty &= ~(BM_EDGE | BM_VERT);
}
-/* BMesh version of BKE_mesh_normals_loop_split() in mesh_evaluate.c */
-static void bm_mesh_loops_calc_normals(BMesh *bm, const float (*vcos)[3], const float (*fnos)[3], float (*r_lnos)[3])
+/* BMesh version of BKE_mesh_normals_loop_split() in mesh_evaluate.c
+ * Will use first clnors_data array, and fallback to cd_loop_clnors_offset (use NULL and -1 to not use clnors). */
+static void bm_mesh_loops_calc_normals(
+ BMesh *bm, const float (*vcos)[3], const float (*fnos)[3], float (*r_lnos)[3],
+ MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2], const int cd_loop_clnors_offset)
{
BMIter fiter;
BMFace *f_curr;
+ const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1);
+
+ MLoopNorSpaceArray _lnors_spacearr = {NULL};
/* Temp normal stack. */
BLI_SMALLSTACK_DECLARE(normal, float *);
+ /* Temp clnors stack. */
+ BLI_SMALLSTACK_DECLARE(clnors, short *);
+ /* Temp edge vectors stack, only used when computing lnor spacearr. */
+ BLI_Stack *edge_vectors = NULL;
{
char htype = BM_LOOP;
@@ -525,6 +553,15 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, const float (*vcos)[3], const
BM_mesh_elem_index_ensure(bm, htype);
}
+ if (!r_lnors_spacearr && has_clnors) {
+ /* We need to compute lnor spacearr if some custom lnor data are given to us! */
+ r_lnors_spacearr = &_lnors_spacearr;
+ }
+ if (r_lnors_spacearr) {
+ BKE_lnor_spacearr_init(r_lnors_spacearr, bm->totloop);
+ edge_vectors = BLI_stack_new(sizeof(float[3]), __func__);
+ }
+
/* We now know edges that can be smoothed (they are tagged), and edges that will be hard (they aren't).
* Now, time to generate the normals.
*/
@@ -533,8 +570,10 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, const float (*vcos)[3], const
l_curr = l_first = BM_FACE_FIRST_LOOP(f_curr);
do {
- if (BM_elem_flag_test_bool(l_curr->e, BM_ELEM_TAG)) {
- /* A smooth edge.
+ if (BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) &&
+ (!r_lnors_spacearr || BM_elem_flag_test(l_curr->v, BM_ELEM_TAG)))
+ {
+ /* A smooth edge, and we are not generating lnors_spacearr, or the related vertex is sharp.
* We skip it because it is either:
* - in the middle of a 'smooth fan' already computed (or that will be as soon as we hit
* one of its ends, i.e. one of its two sharp edges), or...
@@ -542,12 +581,45 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, const float (*vcos)[3], const
* are just fine!
*/
}
- else if (!BM_elem_flag_test_bool(l_curr->prev->e, BM_ELEM_TAG)) {
+ else if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) &&
+ !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG))
+ {
/* Simple case (both edges around that vertex are sharp in related polygon),
* this vertex just takes its poly normal.
*/
+ const int l_curr_index = BM_elem_index_get(l_curr);
const float *no = fnos ? fnos[BM_elem_index_get(f_curr)] : f_curr->no;
- copy_v3_v3(r_lnos[BM_elem_index_get(l_curr)], no);
+ copy_v3_v3(r_lnos[l_curr_index], no);
+
+ /* If needed, generate this (simple!) lnor space. */
+ if (r_lnors_spacearr) {
+ float vec_curr[3], vec_prev[3];
+ MLoopNorSpace *lnor_space = BKE_lnor_space_create(r_lnors_spacearr);
+
+ {
+ const BMVert *v_pivot = l_curr->v;
+ const float *co_pivot = vcos ? vcos[BM_elem_index_get(v_pivot)] : v_pivot->co;
+ const BMVert *v_1 = BM_edge_other_vert(l_curr->e, v_pivot);
+ const float *co_1 = vcos ? vcos[BM_elem_index_get(v_1)] : v_1->co;
+ const BMVert *v_2 = BM_edge_other_vert(l_curr->prev->e, v_pivot);
+ const float *co_2 = vcos ? vcos[BM_elem_index_get(v_2)] : v_2->co;
+
+ sub_v3_v3v3(vec_curr, co_1, co_pivot);
+ normalize_v3(vec_curr);
+ sub_v3_v3v3(vec_prev, co_2, co_pivot);
+ normalize_v3(vec_prev);
+ }
+
+ BKE_lnor_space_define(lnor_space, r_lnos[l_curr_index], vec_curr, vec_prev, NULL);
+ /* We know there is only one loop in this space, no need to create a linklist in this case... */
+ BKE_lnor_space_add_loop(r_lnors_spacearr, lnor_space, l_curr_index, false);
+
+ if (has_clnors) {
+ short (*clnor)[2] = clnors_data ? &clnors_data[l_curr_index] :
+ BM_ELEM_CD_GET_VOID_P(l_curr, cd_loop_clnors_offset);
+ BKE_lnor_space_custom_data_to_normal(lnor_space, *clnor, r_lnos[l_curr_index]);
+ }
+ }
}
/* We *do not need* to check/tag loops as already computed!
* Due to the fact a loop only links to one of its two edges, a same fan *will never be walked more than
@@ -567,13 +639,26 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, const float (*vcos)[3], const
*/
BMVert *v_pivot = l_curr->v;
BMEdge *e_next;
+ const BMEdge *e_org = l_curr->e;
BMLoop *lfan_pivot, *lfan_pivot_next;
+ int lfan_pivot_index;
float lnor[3] = {0.0f, 0.0f, 0.0f};
- float vec_curr[3], vec_next[3];
+ float vec_curr[3], vec_next[3], vec_org[3];
+
+ /* We validate clnors data on the fly - cheapest way to do! */
+ int clnors_avg[2] = {0, 0};
+ short (*clnor_ref)[2] = NULL;
+ int clnors_nbr = 0;
+ bool clnors_invalid = false;
const float *co_pivot = vcos ? vcos[BM_elem_index_get(v_pivot)] : v_pivot->co;
+ MLoopNorSpace *lnor_space = r_lnors_spacearr ? BKE_lnor_space_create(r_lnors_spacearr) : NULL;
+
+ BLI_assert((edge_vectors == NULL) || BLI_stack_is_empty(edge_vectors));
+
lfan_pivot = l_curr;
+ lfan_pivot_index = BM_elem_index_get(lfan_pivot);
e_next = lfan_pivot->e; /* Current edge here, actually! */
/* Only need to compute previous edge's vector once, then we can just reuse old current one! */
@@ -581,8 +666,13 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, const float (*vcos)[3], const
const BMVert *v_2 = BM_edge_other_vert(e_next, v_pivot);
const float *co_2 = vcos ? vcos[BM_elem_index_get(v_2)] : v_2->co;
- sub_v3_v3v3(vec_curr, co_2, co_pivot);
- normalize_v3(vec_curr);
+ sub_v3_v3v3(vec_org, co_2, co_pivot);
+ normalize_v3(vec_org);
+ copy_v3_v3(vec_curr, vec_org);
+
+ if (r_lnors_spacearr) {
+ BLI_stack_push(edge_vectors, vec_org);
+ }
}
while (true) {
@@ -617,12 +707,38 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, const float (*vcos)[3], const
const float *no = fnos ? fnos[BM_elem_index_get(f)] : f->no;
/* Accumulate */
madd_v3_v3fl(lnor, no, fac);
+
+ if (has_clnors) {
+ /* Accumulate all clnors, if they are not all equal we have to fix that! */
+ short (*clnor)[2] = clnors_data ? &clnors_data[lfan_pivot_index] :
+ BM_ELEM_CD_GET_VOID_P(lfan_pivot, cd_loop_clnors_offset);
+ if (clnors_nbr) {
+ clnors_invalid |= ((*clnor_ref)[0] != (*clnor)[0] || (*clnor_ref)[1] != (*clnor)[1]);
+ }
+ else {
+ clnor_ref = clnor;
+ }
+ clnors_avg[0] += (*clnor)[0];
+ clnors_avg[1] += (*clnor)[1];
+ clnors_nbr++;
+ /* We store here a pointer to all custom lnors processed. */
+ BLI_SMALLSTACK_PUSH(clnors, (short *)*clnor);
+ }
}
/* We store here a pointer to all loop-normals processed. */
- BLI_SMALLSTACK_PUSH(normal, (float *)r_lnos[BM_elem_index_get(lfan_pivot)]);
+ BLI_SMALLSTACK_PUSH(normal, (float *)r_lnos[lfan_pivot_index]);
+
+ if (r_lnors_spacearr) {
+ /* Assign current lnor space to current 'vertex' loop. */
+ BKE_lnor_space_add_loop(r_lnors_spacearr, lnor_space, lfan_pivot_index, true);
+ if (e_next != e_org) {
+ /* We store here all edges-normalized vectors processed. */
+ BLI_stack_push(edge_vectors, vec_next);
+ }
+ }
- if (!BM_elem_flag_test_bool(e_next, BM_ELEM_TAG)) {
+ if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) {
/* Next edge is sharp, we have finished with this fan of faces around this vert! */
break;
}
@@ -631,23 +747,105 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, const float (*vcos)[3], const
copy_v3_v3(vec_curr, vec_next);
/* Next pivot loop to current one. */
lfan_pivot = lfan_pivot_next;
+ lfan_pivot_index = BM_elem_index_get(lfan_pivot);
}
- /* In case we get a zero normal here, just use vertex normal already set! */
- if (LIKELY(normalize_v3(lnor) != 0.0f)) {
- /* Copy back the final computed normal into all related loop-normals. */
- float *nor;
- while ((nor = BLI_SMALLSTACK_POP(normal))) {
- copy_v3_v3(nor, lnor);
+ {
+ float lnor_len = normalize_v3(lnor);
+
+ /* If we are generating lnor spacearr, we can now define the one for this fan. */
+ if (r_lnors_spacearr) {
+ if (UNLIKELY(lnor_len == 0.0f)) {
+ /* Use vertex normal as fallback! */
+ copy_v3_v3(lnor, r_lnos[lfan_pivot_index]);
+ lnor_len = 1.0f;
+ }
+
+ BKE_lnor_space_define(lnor_space, lnor, vec_org, vec_next, edge_vectors);
+
+ if (has_clnors) {
+ if (clnors_invalid) {
+ short *clnor;
+
+ clnors_avg[0] /= clnors_nbr;
+ clnors_avg[1] /= clnors_nbr;
+ /* Fix/update all clnors of this fan with computed average value. */
+ printf("Invalid clnors in this fan!\n");
+ while ((clnor = BLI_SMALLSTACK_POP(clnors))) {
+ //print_v2("org clnor", clnor);
+ clnor[0] = (short)clnors_avg[0];
+ clnor[1] = (short)clnors_avg[1];
+ }
+ //print_v2("new clnors", clnors_avg);
+ }
+ else {
+ /* We still have to consume the stack! */
+ while (BLI_SMALLSTACK_POP(clnors));
+ }
+ BKE_lnor_space_custom_data_to_normal(lnor_space, *clnor_ref, lnor);
+ }
+ }
+
+ /* In case we get a zero normal here, just use vertex normal already set! */
+ if (LIKELY(lnor_len != 0.0f)) {
+ /* Copy back the final computed normal into all related loop-normals. */
+ float *nor;
+
+ while ((nor = BLI_SMALLSTACK_POP(normal))) {
+ copy_v3_v3(nor, lnor);
+ }
+ }
+ else {
+ /* We still have to consume the stack! */
+ while (BLI_SMALLSTACK_POP(normal));
}
}
- else {
- /* We still have to clear the stack! */
- while (BLI_SMALLSTACK_POP(normal));
+
+ /* Tag related vertex as sharp, to avoid fanning around it again (in case it was a smooth one). */
+ if (r_lnors_spacearr) {
+ BM_elem_flag_enable(l_curr->v, BM_ELEM_TAG);
}
}
} while ((l_curr = l_curr->next) != l_first);
}
+
+ if (r_lnors_spacearr) {
+ BLI_stack_free(edge_vectors);
+ if (r_lnors_spacearr == &_lnors_spacearr) {
+ BKE_lnor_spacearr_free(r_lnors_spacearr);
+ }
+ }
+}
+
+static void bm_mesh_loops_calc_normals_no_autosmooth(
+ BMesh *bm, const float (*vnos)[3], const float (*fnos)[3], float (*r_lnos)[3])
+{
+ BMIter fiter;
+ BMFace *f_curr;
+
+ {
+ char htype = BM_LOOP;
+ if (vnos) {
+ htype |= BM_VERT;
+ }
+ if (fnos) {
+ htype |= BM_FACE;
+ }
+ BM_mesh_elem_index_ensure(bm, htype);
+ }
+
+ BM_ITER_MESH (f_curr, &fiter, bm, BM_FACES_OF_MESH) {
+ BMLoop *l_curr, *l_first;
+ const bool is_face_flat = !BM_elem_flag_test(f_curr, BM_ELEM_SMOOTH);
+
+ l_curr = l_first = BM_FACE_FIRST_LOOP(f_curr);
+ do {
+ const float *no = is_face_flat ? (fnos ? fnos[BM_elem_index_get(f_curr)] : f_curr->no) :
+ (vnos ? vnos[BM_elem_index_get(l_curr->v)] : l_curr->v->no);
+ copy_v3_v3(r_lnos[BM_elem_index_get(l_curr)], no);
+
+ } while ((l_curr = l_curr->next) != l_first);
+ }
}
#if 0 /* Unused currently */
@@ -657,13 +855,24 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, const float (*vcos)[3], const
* Updates the loop normals of a mesh. Assumes vertex and face normals are valid (else call BM_mesh_normals_update()
* first)!
*/
-void BM_mesh_loop_normals_update(BMesh *bm, const float split_angle, float (*r_lnos)[3])
+void BM_mesh_loop_normals_update(
+ BMesh *bm, const bool use_split_normals, const float split_angle, float (*r_lnos)[3],
+ MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2], const int cd_loop_clnors_offset)
{
- /* Tag smooth edges and set lnos from vnos when they might be completely smooth... */
- bm_mesh_edges_sharp_tag(bm, NULL, NULL, split_angle, r_lnos);
+ const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1);
- /* Finish computing lnos by accumulating face normals in each fan of faces defined by sharp edges. */
- bm_mesh_loops_calc_normals(bm, NULL, NULL, r_lnos);
+ if (use_split_normals) {
+ /* Tag smooth edges and set lnos from vnos when they might be completely smooth...
+ * When using custom loop normals, disable the angle feature! */
+ bm_mesh_edges_sharp_tag(bm, NULL, NULL, has_clnors ? (float)M_PI : split_angle, r_lnos);
+
+ /* Finish computing lnos by accumulating face normals in each fan of faces defined by sharp edges. */
+ bm_mesh_loops_calc_normals(bm, NULL, NULL, r_lnos, r_lnors_spacearr, clnors_data, cd_loop_clnors_offset);
+ }
+ else {
+ BLI_assert(!r_lnors_spacearr);
+ bm_mesh_loops_calc_normals_no_autosmooth(bm, NULL, NULL, r_lnos);
+ }
}
#endif
@@ -673,14 +882,25 @@ void BM_mesh_loop_normals_update(BMesh *bm, const float split_angle, float (*r_l
* Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals').
* Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry (splitting edges).
*/
-void BM_loops_calc_normal_vcos(BMesh *bm, const float (*vcos)[3], const float (*vnos)[3], const float (*fnos)[3],
- const float split_angle, float (*r_lnos)[3])
+void BM_loops_calc_normal_vcos(
+ BMesh *bm, const float (*vcos)[3], const float (*vnos)[3], const float (*fnos)[3],
+ const bool use_split_normals, const float split_angle, float (*r_lnos)[3],
+ MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2], const int cd_loop_clnors_offset)
{
- /* Tag smooth edges and set lnos from vnos when they might be completely smooth... */
- bm_mesh_edges_sharp_tag(bm, vnos, fnos, split_angle, r_lnos);
+ const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1);
+
+ if (use_split_normals) {
+ /* Tag smooth edges and set lnos from vnos when they might be completely smooth...
+ * When using custom loop normals, disable the angle feature! */
+ bm_mesh_edges_sharp_tag(bm, vnos, fnos, has_clnors ? (float)M_PI : split_angle, r_lnos);
- /* Finish computing lnos by accumulating face normals in each fan of faces defined by sharp edges. */
- bm_mesh_loops_calc_normals(bm, vcos, fnos, r_lnos);
+ /* Finish computing lnos by accumulating face normals in each fan of faces defined by sharp edges. */
+ bm_mesh_loops_calc_normals(bm, vcos, fnos, r_lnos, r_lnors_spacearr, clnors_data, cd_loop_clnors_offset);
+ }
+ else {
+ BLI_assert(!r_lnors_spacearr);
+ bm_mesh_loops_calc_normals_no_autosmooth(bm, vnos, fnos, r_lnos);
+ }
}
static void UNUSED_FUNCTION(bm_mdisps_space_set)(Object *ob, BMesh *bm, int from, int to)
@@ -913,8 +1133,9 @@ finally:
* These functions ensure its correct and are called more often in debug mode.
*/
-void BM_mesh_elem_index_validate(BMesh *bm, const char *location, const char *func,
- const char *msg_a, const char *msg_b)
+void BM_mesh_elem_index_validate(
+ BMesh *bm, const char *location, const char *func,
+ const char *msg_a, const char *msg_b)
{
const char iter_types[3] = {BM_VERTS_OF_MESH,
BM_EDGES_OF_MESH,
@@ -1161,6 +1382,41 @@ BMFace *BM_face_at_index_find(BMesh *bm, const int index)
return BLI_mempool_findelem(bm->fpool, index);
}
+/**
+ * Use lookup table when available, else use slower find functions.
+ *
+ * \note Try to use #BM_mesh_elem_table_ensure instead.
+ */
+BMVert *BM_vert_at_index_find_or_table(BMesh *bm, const int index)
+{
+ if ((bm->elem_table_dirty & BM_VERT) == 0) {
+ return (index < bm->totvert) ? bm->vtable[index] : NULL;
+ }
+ else {
+ return BM_vert_at_index_find(bm, index);
+ }
+}
+
+BMEdge *BM_edge_at_index_find_or_table(BMesh *bm, const int index)
+{
+ if ((bm->elem_table_dirty & BM_EDGE) == 0) {
+ return (index < bm->totedge) ? bm->etable[index] : NULL;
+ }
+ else {
+ return BM_edge_at_index_find(bm, index);
+ }
+}
+
+BMFace *BM_face_at_index_find_or_table(BMesh *bm, const int index)
+{
+ if ((bm->elem_table_dirty & BM_FACE) == 0) {
+ return (index < bm->totface) ? bm->ftable[index] : NULL;
+ }
+ else {
+ return BM_face_at_index_find(bm, index);
+ }
+}
+
/**
* Return the amount of element of type 'type' in a given bmesh.
@@ -1182,6 +1438,24 @@ int BM_mesh_elem_count(BMesh *bm, const char htype)
}
/**
+ * Special case: Python uses custom-data layers to hold PyObject references.
+ * These have to be kept in-place, else the PyObject's we point to, wont point back to us.
+ *
+ * \note ``ele_src`` Is a duplicate, so we don't need to worry about getting in a feedback loop.
+ *
+ * \note If there are other customdata layers which need this functionality, it should be generalized.
+ * However #BM_mesh_remap is currently the only place where this is done.
+ */
+static void bm_mesh_remap_cd_update(
+ BMHeader *ele_dst, BMHeader *ele_src,
+ const int cd_elem_pyptr)
+{
+ void **pyptr_dst_p = BM_ELEM_CD_GET_VOID_P(((BMElem *)ele_dst), cd_elem_pyptr);
+ void **pyptr_src_p = BM_ELEM_CD_GET_VOID_P(((BMElem *)ele_src), cd_elem_pyptr);
+ *pyptr_dst_p = *pyptr_src_p;
+}
+
+/**
* Remaps the vertices, edges and/or faces of the bmesh as indicated by vert/edge/face_idx arrays
* (xxx_idx[org_index] = new_index).
*
@@ -1221,6 +1495,7 @@ void BM_mesh_remap(
BMVert **verts_pool, *verts_copy, **vep;
int i, totvert = bm->totvert;
const unsigned int *new_idx;
+ const int cd_vert_pyptr = CustomData_get_offset(&bm->vdata, CD_BM_ELEM_PYPTR);
/* Init the old-to-new vert pointers mapping */
vptr_map = BLI_ghash_ptr_new_ex("BM_mesh_remap vert pointers mapping", bm->totvert);
@@ -1241,7 +1516,10 @@ void BM_mesh_remap(
BMVert *new_vep = verts_pool[*new_idx];
*new_vep = *ve;
/* printf("mapping vert from %d to %d (%p/%p to %p)\n", i, *new_idx, *vep, verts_pool[i], new_vep);*/
- BLI_ghash_insert(vptr_map, (void *)*vep, (void *)new_vep);
+ BLI_ghash_insert(vptr_map, *vep, new_vep);
+ if (cd_vert_pyptr != -1) {
+ bm_mesh_remap_cd_update(&(*vep)->head, &new_vep->head, cd_vert_pyptr);
+ }
}
bm->elem_index_dirty |= BM_VERT;
bm->elem_table_dirty |= BM_VERT;
@@ -1254,6 +1532,7 @@ void BM_mesh_remap(
BMEdge **edges_pool, *edges_copy, **edp;
int i, totedge = bm->totedge;
const unsigned int *new_idx;
+ const int cd_edge_pyptr = CustomData_get_offset(&bm->edata, CD_BM_ELEM_PYPTR);
/* Init the old-to-new vert pointers mapping */
eptr_map = BLI_ghash_ptr_new_ex("BM_mesh_remap edge pointers mapping", bm->totedge);
@@ -1272,8 +1551,11 @@ void BM_mesh_remap(
for (i = totedge; i--; new_idx--, ed--, edp--) {
BMEdge *new_edp = edges_pool[*new_idx];
*new_edp = *ed;
- BLI_ghash_insert(eptr_map, (void *)*edp, (void *)new_edp);
+ BLI_ghash_insert(eptr_map, *edp, new_edp);
/* printf("mapping edge from %d to %d (%p/%p to %p)\n", i, *new_idx, *edp, edges_pool[i], new_edp);*/
+ if (cd_edge_pyptr != -1) {
+ bm_mesh_remap_cd_update(&(*edp)->head, &new_edp->head, cd_edge_pyptr);
+ }
}
bm->elem_index_dirty |= BM_EDGE;
bm->elem_table_dirty |= BM_EDGE;
@@ -1286,6 +1568,7 @@ void BM_mesh_remap(
BMFace **faces_pool, *faces_copy, **fap;
int i, totface = bm->totface;
const unsigned int *new_idx;
+ const int cd_poly_pyptr = CustomData_get_offset(&bm->pdata, CD_BM_ELEM_PYPTR);
/* Init the old-to-new vert pointers mapping */
fptr_map = BLI_ghash_ptr_new_ex("BM_mesh_remap face pointers mapping", bm->totface);
@@ -1304,7 +1587,10 @@ void BM_mesh_remap(
for (i = totface; i--; new_idx--, fa--, fap--) {
BMFace *new_fap = faces_pool[*new_idx];
*new_fap = *fa;
- BLI_ghash_insert(fptr_map, (void *)*fap, (void *)new_fap);
+ BLI_ghash_insert(fptr_map, *fap, new_fap);
+ if (cd_poly_pyptr != -1) {
+ bm_mesh_remap_cd_update(&(*fap)->head, &new_fap->head, cd_poly_pyptr);
+ }
}
bm->elem_index_dirty |= BM_FACE | BM_LOOP;
@@ -1317,8 +1603,11 @@ void BM_mesh_remap(
/* Verts' pointers, only edge pointers... */
if (eptr_map) {
BM_ITER_MESH (ve, &iter, bm, BM_VERTS_OF_MESH) {
-/* printf("Vert e: %p -> %p\n", ve->e, BLI_ghash_lookup(eptr_map, (const void *)ve->e));*/
- ve->e = BLI_ghash_lookup(eptr_map, (const void *)ve->e);
+/* printf("Vert e: %p -> %p\n", ve->e, BLI_ghash_lookup(eptr_map, ve->e));*/
+ if (ve->e) {
+ ve->e = BLI_ghash_lookup(eptr_map, ve->e);
+ BLI_assert(ve->e);
+ }
}
}
@@ -1327,24 +1616,30 @@ void BM_mesh_remap(
if (vptr_map || eptr_map) {
BM_ITER_MESH (ed, &iter, bm, BM_EDGES_OF_MESH) {
if (vptr_map) {
-/* printf("Edge v1: %p -> %p\n", ed->v1, BLI_ghash_lookup(vptr_map, (const void *)ed->v1));*/
-/* printf("Edge v2: %p -> %p\n", ed->v2, BLI_ghash_lookup(vptr_map, (const void *)ed->v2));*/
- ed->v1 = BLI_ghash_lookup(vptr_map, (const void *)ed->v1);
- ed->v2 = BLI_ghash_lookup(vptr_map, (const void *)ed->v2);
+/* printf("Edge v1: %p -> %p\n", ed->v1, BLI_ghash_lookup(vptr_map, ed->v1));*/
+/* printf("Edge v2: %p -> %p\n", ed->v2, BLI_ghash_lookup(vptr_map, ed->v2));*/
+ ed->v1 = BLI_ghash_lookup(vptr_map, ed->v1);
+ ed->v2 = BLI_ghash_lookup(vptr_map, ed->v2);
+ BLI_assert(ed->v1);
+ BLI_assert(ed->v2);
}
if (eptr_map) {
/* printf("Edge v1_disk_link prev: %p -> %p\n", ed->v1_disk_link.prev,*/
-/* BLI_ghash_lookup(eptr_map, (const void *)ed->v1_disk_link.prev));*/
+/* BLI_ghash_lookup(eptr_map, ed->v1_disk_link.prev));*/
/* printf("Edge v1_disk_link next: %p -> %p\n", ed->v1_disk_link.next,*/
-/* BLI_ghash_lookup(eptr_map, (const void *)ed->v1_disk_link.next));*/
+/* BLI_ghash_lookup(eptr_map, ed->v1_disk_link.next));*/
/* printf("Edge v2_disk_link prev: %p -> %p\n", ed->v2_disk_link.prev,*/
-/* BLI_ghash_lookup(eptr_map, (const void *)ed->v2_disk_link.prev));*/
+/* BLI_ghash_lookup(eptr_map, ed->v2_disk_link.prev));*/
/* printf("Edge v2_disk_link next: %p -> %p\n", ed->v2_disk_link.next,*/
-/* BLI_ghash_lookup(eptr_map, (const void *)ed->v2_disk_link.next));*/
- ed->v1_disk_link.prev = BLI_ghash_lookup(eptr_map, (const void *)ed->v1_disk_link.prev);
- ed->v1_disk_link.next = BLI_ghash_lookup(eptr_map, (const void *)ed->v1_disk_link.next);
- ed->v2_disk_link.prev = BLI_ghash_lookup(eptr_map, (const void *)ed->v2_disk_link.prev);
- ed->v2_disk_link.next = BLI_ghash_lookup(eptr_map, (const void *)ed->v2_disk_link.next);
+/* BLI_ghash_lookup(eptr_map, ed->v2_disk_link.next));*/
+ ed->v1_disk_link.prev = BLI_ghash_lookup(eptr_map, ed->v1_disk_link.prev);
+ ed->v1_disk_link.next = BLI_ghash_lookup(eptr_map, ed->v1_disk_link.next);
+ ed->v2_disk_link.prev = BLI_ghash_lookup(eptr_map, ed->v2_disk_link.prev);
+ ed->v2_disk_link.next = BLI_ghash_lookup(eptr_map, ed->v2_disk_link.next);
+ BLI_assert(ed->v1_disk_link.prev);
+ BLI_assert(ed->v1_disk_link.next);
+ BLI_assert(ed->v2_disk_link.prev);
+ BLI_assert(ed->v2_disk_link.next);
}
}
}
@@ -1353,16 +1648,19 @@ void BM_mesh_remap(
BM_ITER_MESH (fa, &iter, bm, BM_FACES_OF_MESH) {
BM_ITER_ELEM (lo, &iterl, fa, BM_LOOPS_OF_FACE) {
if (vptr_map) {
-/* printf("Loop v: %p -> %p\n", lo->v, BLI_ghash_lookup(vptr_map, (const void *)lo->v));*/
- lo->v = BLI_ghash_lookup(vptr_map, (const void *)lo->v);
+/* printf("Loop v: %p -> %p\n", lo->v, BLI_ghash_lookup(vptr_map, lo->v));*/
+ lo->v = BLI_ghash_lookup(vptr_map, lo->v);
+ BLI_assert(lo->v);
}
if (eptr_map) {
-/* printf("Loop e: %p -> %p\n", lo->e, BLI_ghash_lookup(eptr_map, (const void *)lo->e));*/
- lo->e = BLI_ghash_lookup(eptr_map, (const void *)lo->e);
+/* printf("Loop e: %p -> %p\n", lo->e, BLI_ghash_lookup(eptr_map, lo->e));*/
+ lo->e = BLI_ghash_lookup(eptr_map, lo->e);
+ BLI_assert(lo->e);
}
if (fptr_map) {
-/* printf("Loop f: %p -> %p\n", lo->f, BLI_ghash_lookup(fptr_map, (const void *)lo->f));*/
- lo->f = BLI_ghash_lookup(fptr_map, (const void *)lo->f);
+/* printf("Loop f: %p -> %p\n", lo->f, BLI_ghash_lookup(fptr_map, lo->f));*/
+ lo->f = BLI_ghash_lookup(fptr_map, lo->f);
+ BLI_assert(lo->f);
}
}
}