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>2020-02-14 12:38:39 +0300
committerCampbell Barton <ideasman42@gmail.com>2020-02-14 12:38:39 +0300
commit9fef5a2db43b7146c8c734fe15232c30fda3f796 (patch)
tree59bdf75fbb3a04b91e7717bb05fc334af4256314 /source/blender/bmesh
parent59bae6d149445ec3b24576d7d134f35415d2eba6 (diff)
Fix T71971: Inset with depth and relative offset fails
Diffstat (limited to 'source/blender/bmesh')
-rw-r--r--source/blender/bmesh/operators/bmo_inset.c165
1 files changed, 156 insertions, 9 deletions
diff --git a/source/blender/bmesh/operators/bmo_inset.c b/source/blender/bmesh/operators/bmo_inset.c
index 1570c802bee..255831195b0 100644
--- a/source/blender/bmesh/operators/bmo_inset.c
+++ b/source/blender/bmesh/operators/bmo_inset.c
@@ -26,6 +26,8 @@
#include "BLI_math.h"
#include "BLI_alloca.h"
#include "BLI_memarena.h"
+#include "BLI_utildefines_stack.h"
+
#include "BKE_customdata.h"
#include "bmesh.h"
@@ -512,8 +514,138 @@ static float bm_edge_info_average_length(BMVert *v, SplitEdgeInfo *edge_info)
}
}
- BLI_assert(tot != 0);
- return len / (float)tot;
+ if (tot != 0) {
+ return len / (float)tot;
+ }
+ else {
+ return -1.0f;
+ }
+}
+
+/**.
+ * Fill in any central vertex locations by their connected edges.
+ *
+ * This is lazily initialized since it's a relatively expensive operation,
+ * and it's not needed in cases where all vertices being inset are connected to
+ * edges that are part of the inset.
+ */
+static float bm_edge_info_average_length_fallback(BMVert *v_lookup,
+ SplitEdgeInfo *edge_info,
+ BMesh *bm,
+ void **vert_lengths_p)
+{
+ struct {
+ /**
+ * Use to fill in length accumulated values based on the topological distance
+ * to vertices at the inset boundaries.
+ *
+ * Unlike edge-lengths of vertices immediately around the vertex,
+ * this ensures the values are more evenly distributed.
+ */
+ float length_accum;
+ /**
+ * The number of connected vertices we have added to `length_accum`.
+ * The sign of the value is used to avoid mixing current and previous passes.
+ *
+ * - Zero: Uninitialized, can be added to `vert_stack`.
+ * - Positive: Part of the current pass, `length_accum` has not yet been divided.
+ * - Minus One: Part of previous passes, `length_accum` value has been divided.
+ */
+ int count;
+ } *vert_lengths = *vert_lengths_p;
+
+ /* Only run this once, if needed. */
+ if (UNLIKELY(vert_lengths == NULL)) {
+ BMVert **vert_stack = MEM_mallocN(sizeof(*vert_stack) * bm->totvert, __func__);
+ STACK_DECLARE(vert_stack);
+ STACK_INIT(vert_stack, bm->totvert);
+
+ vert_lengths = MEM_callocN(sizeof(*vert_lengths) * bm->totvert, __func__);
+
+ /* Needed for 'vert_lengths' lookup from connected vertices. */
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+
+ {
+ BMIter iter;
+ BMEdge *e;
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_index_get(e) != -1) {
+ for (int i = 0; i < 2; i++) {
+ BMVert *v = *((&e->v1) + i);
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ const int v_index = BM_elem_index_get(v);
+ if (vert_lengths[v_index].count == 0) {
+ STACK_PUSH(vert_stack, v);
+ /* Needed for the first pass, avoid a separate loop to handle the first pass. */
+ vert_lengths[v_index].count = 1;
+ /* We know the edge lengths exist in this case, should never be -1. */
+ vert_lengths[v_index].length_accum = bm_edge_info_average_length(v, edge_info);
+ BLI_assert(vert_lengths[v_index].length_accum != -1.0f);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* While there are vertices without their accumulated lengths divided by the count. */
+ while (STACK_SIZE(vert_stack) != 0) {
+ int stack_index = STACK_SIZE(vert_stack);
+ while (stack_index--) {
+ BMVert *v = vert_stack[stack_index];
+ STACK_REMOVE(vert_stack, stack_index);
+ const int v_index = BM_elem_index_get(v);
+
+ BLI_assert(vert_lengths[v_index].count > 0);
+ vert_lengths[v_index].length_accum /= (float)vert_lengths[v_index].count;
+ vert_lengths[v_index].count = -1; /* Ignore in future passes. */
+
+ BMIter iter;
+ BMEdge *e;
+ BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
+ if (!BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ continue;
+ }
+ BMVert *v_other = BM_edge_other_vert(e, v);
+ if (!BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
+ continue;
+ }
+ int v_other_index = BM_elem_index_get(v_other);
+ if (vert_lengths[v_other_index].count >= 0) {
+ if (vert_lengths[v_other_index].count == 0) {
+ STACK_PUSH(vert_stack, v_other);
+ }
+ BLI_assert(vert_lengths[v_index].length_accum >= 0.0f);
+ vert_lengths[v_other_index].count += 1;
+ vert_lengths[v_other_index].length_accum += vert_lengths[v_index].length_accum;
+ }
+ }
+ }
+ }
+ MEM_freeN(vert_stack);
+ *vert_lengths_p = vert_lengths;
+ }
+
+ BLI_assert(vert_lengths[BM_elem_index_get(v_lookup)].length_accum >= 0.0f);
+ return vert_lengths[BM_elem_index_get(v_lookup)].length_accum;
+}
+
+static float bm_edge_info_average_length_with_fallback(
+ BMVert *v,
+ SplitEdgeInfo *edge_info,
+
+ /* Needed for 'bm_edge_info_average_length_fallback' */
+ BMesh *bm,
+ void **vert_lengths_p)
+{
+
+ const float length = bm_edge_info_average_length(v, edge_info);
+ if (length != -1.0f) {
+ return length;
+ }
+ else {
+ return bm_edge_info_average_length_fallback(v, edge_info, bm, vert_lengths_p);
+ }
}
/**
@@ -1193,9 +1325,12 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
/* tag face verts */
BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) {
- BM_ITER_ELEM (v, &iter, f, BM_VERTS_OF_FACE) {
- BM_elem_flag_enable(v, BM_ELEM_TAG);
- }
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG);
+ BM_elem_flag_enable(l_iter->e, BM_ELEM_TAG);
+ } while ((l_iter = l_iter->next) != l_first);
}
/* do in 2 passes so moving the verts doesn't feed back into face angle checks
@@ -1203,17 +1338,29 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
/* over allocate */
varr_co = MEM_callocN(sizeof(*varr_co) * bm->totvert, __func__);
+ void *vert_lengths_p = NULL;
BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
- const float fac = (depth *
- (use_relative_offset ? bm_edge_info_average_length(v, edge_info) :
- 1.0f) *
- (use_even_boundary ? BM_vert_calc_shell_factor(v) : 1.0f));
+ const float fac =
+ depth *
+ (use_relative_offset ?
+ bm_edge_info_average_length_with_fallback(
+ v,
+ edge_info,
+ /* Variables needed for filling interior values for vertex lengths. */
+ bm,
+ &vert_lengths_p) :
+ 1.0f) *
+ (use_even_boundary ? BM_vert_calc_shell_factor(v) : 1.0f);
madd_v3_v3v3fl(varr_co[i], v->co, v->no, fac);
}
}
+ if (vert_lengths_p != NULL) {
+ MEM_freeN(vert_lengths_p);
+ }
+
BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
copy_v3_v3(v->co, varr_co[i]);