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:
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h3
-rw-r--r--source/blender/blenkernel/intern/brush.c12
-rw-r--r--source/blender/blenkernel/intern/dyntopo.c546
-rw-r--r--source/blender/blenkernel/intern/paint.c7
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c30
-rw-r--r--source/blender/blenlib/BLI_mempool.h11
-rw-r--r--source/blender/blenlib/intern/BLI_mempool.c138
-rw-r--r--source/blender/bmesh/intern/bmesh_log.c6
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c456
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c80
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_dyntopo.c13
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.c165
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h1
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_smooth.c85
14 files changed, 1307 insertions, 246 deletions
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 76adab9168b..afed28d8120 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -33,6 +33,9 @@
extern "C" {
#endif
+// experimental feature to detect quad diagonals and mark (but not dissolve) them
+//#define SCULPT_DIAGONAL_EDGE_MARKS
+
typedef struct SculptVertRef {
intptr_t i;
} SculptVertRef;
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index b0870e0558e..956b69d608f 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -1789,6 +1789,8 @@ void BKE_brush_sculpt_reset(Brush *br)
break;
case SCULPT_TOOL_SMOOTH:
br->flag &= ~BRUSH_SPACE_ATTEN;
+ br->flag2 |= BRUSH_SMOOTH_PRESERVE_FACE_SETS | BRUSH_SMOOTH_USE_AREA_WEIGHT;
+
br->spacing = 5;
br->alpha = 0.7f;
br->surface_smooth_shape_preservation = 0.5f;
@@ -1801,9 +1803,10 @@ void BKE_brush_sculpt_reset(Brush *br)
br->alpha = 1.0f;
br->rake_factor = 1.0f;
br->dyntopo.inherit = DYNTOPO_INHERIT_BITMASK &
- ~(DYNTOPO_INHERIT_ALL | DYNTOPO_LOCAL_COLLAPSE | DYNTOPO_INHERIT_DETAIL_RANGE);
+ ~(DYNTOPO_INHERIT_ALL | DYNTOPO_LOCAL_COLLAPSE |
+ DYNTOPO_INHERIT_DETAIL_RANGE);
br->dyntopo.flag |= DYNTOPO_LOCAL_COLLAPSE;
- br->dyntopo.detail_range = 0.5f;
+ br->dyntopo.detail_range = 0.4f;
break;
case SCULPT_TOOL_THUMB:
br->size = 75;
@@ -1980,13 +1983,14 @@ void BKE_brush_sculpt_reset(Brush *br)
// don't use DYNTOPO_INHERIT_BITMASK, we want to include
// future bits
- br->flag |= BRUSH_SMOOTH_PRESERVE_FACE_SETS | BRUSH_SMOOTH_USE_AREA_WEIGHT |
- BRUSH_CURVATURE_RAKE;
+ br->flag2 |= BRUSH_SMOOTH_PRESERVE_FACE_SETS | BRUSH_SMOOTH_USE_AREA_WEIGHT |
+ BRUSH_CURVATURE_RAKE;
br->dyntopo.inherit = 0x7FFFFFFF &
~(DYNTOPO_INHERIT_ALL | DYNTOPO_SUBDIVIDE | DYNTOPO_COLLAPSE);
br->dyntopo.flag |= DYNTOPO_COLLAPSE | DYNTOPO_SUBDIVIDE;
br->autosmooth_factor = 0.05;
br->topology_rake_factor = 0.35;
+ br->topology_rake_projection = 0.975;
break;
case SCULPT_TOOL_VCOL_BOUNDARY:
diff --git a/source/blender/blenkernel/intern/dyntopo.c b/source/blender/blenkernel/intern/dyntopo.c
index 766a1b95b21..d2324788561 100644
--- a/source/blender/blenkernel/intern/dyntopo.c
+++ b/source/blender/blenkernel/intern/dyntopo.c
@@ -61,16 +61,18 @@
* (avoids performing subdivisions too far away). */
#define EVEN_GENERATION_SCALE 1.1f
-// recursion depth to start applying front face test
+/* recursion depth to start applying front face test */
#define DEPTH_START_LIMIT 5
-//#define FANCY_EDGE_WEIGHTS
-#define SKINNY_EDGE_FIX
+//#define FANCY_EDGE_WEIGHTS <= too slow
+//#define SKINNY_EDGE_FIX
-// slightly relax geometry by this factor along surface tangents
-// to improve convergence of remesher
+/* slightly relax geometry by this factor along surface tangents
+ to improve convergence of remesher */
#define DYNTOPO_SAFE_SMOOTH_FAC 0.05f
+#define DYNTOPO_SAFE_SMOOTH_SUBD_ONLY_FAC 0.75f
+
#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
# include "BKE_global.h"
#endif
@@ -157,8 +159,12 @@ struct EdgeQueueContext;
static bool check_face_is_tri(PBVH *pbvh, BMFace *f);
static bool check_vert_fan_are_tris(PBVH *pbvh, BMVert *v);
-static void pbvh_split_edges(
- PBVH *pbvh, BMesh *bm, BMEdge **edges, int totedge, bool ignore_isolated_edges);
+static void pbvh_split_edges(struct EdgeQueueContext *eq_ctx,
+ PBVH *pbvh,
+ BMesh *bm,
+ BMEdge **edges,
+ int totedge,
+ bool ignore_isolated_edges);
void bm_log_message(const char *fmt, ...);
void pbvh_bmesh_check_nodes_simple(PBVH *pbvh);
static void edge_queue_create_local(struct EdgeQueueContext *eq_ctx,
@@ -458,7 +464,7 @@ static BMEdge *bmesh_edge_create_log(PBVH *pbvh, BMVert *v1, BMVert *v2, BMEdge
return e;
}
-BLI_INLINE void surface_smooth_v_safe(PBVH *pbvh, BMVert *v)
+BLI_INLINE void surface_smooth_v_safe(PBVH *pbvh, BMVert *v, float fac)
{
float co[3];
float tan[3];
@@ -516,9 +522,9 @@ BLI_INLINE void surface_smooth_v_safe(PBVH *pbvh, BMVert *v)
float x = v->co[0], y = v->co[1], z = v->co[2];
// conflicts here should be pretty rare.
- atomic_cas_float(&v->co[0], x, x + co[0] * DYNTOPO_SAFE_SMOOTH_FAC);
- atomic_cas_float(&v->co[1], y, y + co[1] * DYNTOPO_SAFE_SMOOTH_FAC);
- atomic_cas_float(&v->co[2], z, z + co[2] * DYNTOPO_SAFE_SMOOTH_FAC);
+ atomic_cas_float(&v->co[0], x, x + co[0] * fac);
+ atomic_cas_float(&v->co[1], y, y + co[1] * fac);
+ atomic_cas_float(&v->co[2], z, z + co[2] * fac);
}
static void pbvh_kill_vert(PBVH *pbvh, BMVert *v)
@@ -1229,6 +1235,7 @@ typedef struct EdgeQueueContext {
int val34_verts_tot;
int val34_verts_size;
bool local_mode;
+ float surface_smooth_fac;
} EdgeQueueContext;
static void edge_queue_insert_val34_vert(EdgeQueueContext *eq_ctx, BMVert *v)
@@ -1279,9 +1286,15 @@ BLI_INLINE float calc_weighted_edge_split(EdgeQueueContext *eq_ctx, BMVert *v1,
{
#ifdef FANCY_EDGE_WEIGHTS
float l = len_squared_v3v3(v1->co, v2->co);
- float val = (float)BM_vert_edge_count(v1) + (float)BM_vert_edge_count(v2);
- val = MAX2(val * 0.5 - 6.0f, 1.0f);
- val = powf(val, 0.5);
+ // float val = (float)BM_vert_edge_count(v1) + (float)BM_vert_edge_count(v2);
+ MDynTopoVert *mv1 = BKE_PBVH_DYNVERT(eq_ctx->cd_dyn_vert, v1);
+ MDynTopoVert *mv2 = BKE_PBVH_DYNVERT(eq_ctx->cd_dyn_vert, v2);
+ float val = (float)(mv1->valence + mv2->valence) * 0.5f;
+
+ val -= 6.0f;
+ val = MAX2(val, 1.0f);
+
+ // val = powf(val, 0.5);
l *= val;
return l;
@@ -1301,14 +1314,16 @@ BLI_INLINE float calc_weighted_edge_collapse(EdgeQueueContext *eq_ctx, BMVert *v
{
#ifdef FANCY_EDGE_WEIGHTS
float l = len_squared_v3v3(v1->co, v2->co);
- float val = (float)BM_vert_edge_count(v1) + (float)BM_vert_edge_count(v2);
- val = MAX2(val * 0.5 - 6.0f, 1.0f);
- val = powf(val, 0.5);
- l /= val;
+ // float val = (float)BM_vert_edge_count(v1) + (float)BM_vert_edge_count(v2);
+ MDynTopoVert *mv1 = BKE_PBVH_DYNVERT(eq_ctx->cd_dyn_vert, v1);
+ MDynTopoVert *mv2 = BKE_PBVH_DYNVERT(eq_ctx->cd_dyn_vert, v2);
+ float val = (float)(mv1->valence + mv2->valence) * 0.5f;
+
+ val -= 6.0f;
+ val = MAX2(val, 1.0f);
- // if (BM_vert_edge_count(v1) == 4 || BM_vert_edge_count(v2) == 4) {
- // l *= 0.25f;
- //}
+ // val = powf(val, 0.5);
+ l *= val;
return l;
#else
@@ -1548,11 +1563,6 @@ static void long_edge_queue_edge_add_recursive(EdgeQueueContext *eq_ctx,
edge_queue_insert(eq_ctx, l_edge->e, -len_sq, eq_ctx->q->limit_len);
}
- /* temp support previous behavior! */
- if (UNLIKELY(G.debug_value == 1234)) {
- return;
- }
-
if ((l_edge->radial_next != l_edge)) {
const float len_sq_cmp = len_sq * EVEN_EDGELEN_THRESHOLD;
@@ -1678,11 +1688,6 @@ static void short_edge_queue_edge_add_recursive_2(EdgeQueueThreadData *tdata,
edge_thread_data_insert(tdata, l_edge->e);
- /* temp support previous behavior! */
- if (UNLIKELY(G.debug_value == 1234)) {
- return;
- }
-
if ((l_edge->radial_next != l_edge)) {
const float len_sq_cmp = len_sq * EVEN_EDGELEN_THRESHOLD;
@@ -1716,7 +1721,8 @@ static void long_edge_queue_edge_add_recursive_2(EdgeQueueThreadData *tdata,
BMLoop *l_end,
const float len_sq,
float limit_len,
- int depth)
+ int depth,
+ bool insert)
{
BLI_assert(len_sq > square_f(limit_len));
@@ -1732,11 +1738,8 @@ static void long_edge_queue_edge_add_recursive_2(EdgeQueueThreadData *tdata,
}
#endif
- edge_thread_data_insert(tdata, l_edge->e);
-
- /* temp support previous behavior! */
- if (UNLIKELY(G.debug_value == 1234)) {
- return;
+ if (insert) {
+ edge_thread_data_insert(tdata, l_edge->e);
}
if ((l_edge->radial_next != l_edge)) {
@@ -1758,14 +1761,24 @@ static void long_edge_queue_edge_add_recursive_2(EdgeQueueThreadData *tdata,
len_sq_other *= w * w;
- if (len_sq_other > max_ff(len_sq_cmp, limit_len_sq)) {
- long_edge_queue_edge_add_recursive_2(tdata,
- l_adjacent[i]->radial_next,
- l_adjacent[i],
- len_sq_other,
- limit_len,
- depth + 1);
+ bool insert_ok = len_sq_other > max_ff(len_sq_cmp, limit_len_sq);
+#ifdef EVEN_NO_TEST_DEPTH_LIMIT
+ if (!insert_ok && depth >= EVEN_NO_TEST_DEPTH_LIMIT) {
+ continue;
+ }
+#else
+ if (!insert_ok) {
+ continue;
}
+#endif
+
+ long_edge_queue_edge_add_recursive_2(tdata,
+ l_adjacent[i]->radial_next,
+ l_adjacent[i],
+ len_sq_other,
+ limit_len,
+ depth + 1,
+ insert_ok);
}
} while ((l_iter = l_iter->radial_next) != l_end);
}
@@ -1825,8 +1838,8 @@ static void long_edge_queue_task_cb(void *__restrict userdata,
// try to improve convergence by applying a small amount of smoothing to topology,
// but tangentially to surface.
- if (BLI_rng_get_float(rng) > 0.75) {
- surface_smooth_v_safe(tdata->pbvh, l_iter->v);
+ if (BLI_rng_get_float(rng) > 0.5) {
+ surface_smooth_v_safe(tdata->pbvh, l_iter->v, eq_ctx->surface_smooth_fac);
}
#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
@@ -1837,7 +1850,7 @@ static void long_edge_queue_task_cb(void *__restrict userdata,
if (len_sq > eq_ctx->q->limit_len_squared) {
long_edge_queue_edge_add_recursive_2(
- tdata, l_iter->radial_next, l_iter, len_sq, eq_ctx->q->limit_len, 0);
+ tdata, l_iter->radial_next, l_iter, len_sq, eq_ctx->q->limit_len, 0, true);
}
#else
const float len_sq = BM_edge_calc_length_squared(l_iter->e);
@@ -2222,10 +2235,6 @@ static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
if (mv->flag & DYNVERT_NEED_VALENCE) {
BKE_pbvh_bmesh_update_valence(pbvh->cd_dyn_vert, (SculptVertRef){.i = (intptr_t)v});
}
-
- if (mv->valence < 5) {
- edge_queue_insert_val34_vert(eq_ctx, v);
- }
}
BMEdge **edges = td->edges;
@@ -2243,13 +2252,6 @@ static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
BKE_pbvh_bmesh_update_valence(pbvh->cd_dyn_vert, (SculptVertRef){.i = (intptr_t)e->v2});
}
- if (mv1->valence < 5) {
- edge_queue_insert_val34_vert(eq_ctx, e->v1);
- }
- if (mv2->valence < 5) {
- edge_queue_insert_val34_vert(eq_ctx, e->v2);
- }
-
check_vert_fan_are_tris(pbvh, e->v1);
check_vert_fan_are_tris(pbvh, e->v2);
@@ -2375,10 +2377,6 @@ static void edge_queue_create_local(EdgeQueueContext *eq_ctx,
if (mv->flag & DYNVERT_NEED_VALENCE) {
BKE_pbvh_bmesh_update_valence(pbvh->cd_dyn_vert, (SculptVertRef){.i = (intptr_t)v});
}
-
- if (mv->valence == 3 || mv->valence == 4) {
- edge_queue_insert_val34_vert(eq_ctx, v);
- }
}
}
}
@@ -2709,8 +2707,6 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
mv_new->flag |= DYNVERT_NEED_DISK_SORT | DYNVERT_NEED_VALENCE | DYNVERT_NEED_BOUNDARY;
mv_new->flag &= ~DYNVERT_VALENCE_TEMP;
- edge_queue_insert_val34_vert(eq_ctx, v_new);
-
int ni_new2 = BM_ELEM_CD_GET_INT(v_new, pbvh->cd_vert_node_offset);
if (ni_new2 != ni_new) {
// printf("error!\n");
@@ -2965,7 +2961,7 @@ static bool pbvh_bmesh_subdivide_long_edges(
#endif
#ifdef USE_NEW_SPLIT
- pbvh_split_edges(pbvh, pbvh->bm, edges, BLI_array_len(edges), has_cleanup);
+ pbvh_split_edges(eq_ctx, pbvh, pbvh->bm, edges, BLI_array_len(edges), has_cleanup);
BLI_array_free(edges);
#endif
@@ -3159,7 +3155,6 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
// pbvh_bmesh_check_nodes_simple(pbvh);
-#if 1
BM_LOOPS_OF_VERT_ITER_BEGIN (l, v_del) {
BMFace *existing_face;
@@ -3187,11 +3182,11 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
* skip adding this face and mark the existing one for
* deletion as well. Prevents extraneous "flaps" from being
* created. */
-# if 0
+#if 0
if (UNLIKELY(existing_face = BM_face_exists(v_tri, 3)))
-# else
+#else
if (UNLIKELY(existing_face = bm_face_exists_tri_from_loop_vert(l->next, v_conn)))
-# endif
+#endif
{
bool ok2 = true;
@@ -3217,14 +3212,14 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
continue;
}
-# ifdef CHECKMESH
+#ifdef CHECKMESH
int m = 0;
-# define LTEST1(l, bit) \
- if ((l) != (l)->radial_next && (l) == (l)->radial_next->radial_next && \
- (l)->v == (l)->radial_next->v) { \
- m |= 1 << bit; \
- }
+# define LTEST1(l, bit) \
+ if ((l) != (l)->radial_next && (l) == (l)->radial_next->radial_next && \
+ (l)->v == (l)->radial_next->v) { \
+ m |= 1 << bit; \
+ }
if (l->f->len != 3) {
printf("error in %s!!\n", __func__);
@@ -3243,7 +3238,7 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
// SWAP(BMVert *, v_tri[0], v_tri[2]);
// SWAP(BMVert *, old_tri[0], old_tri[2]);
}
-# endif
+#endif
MDynTopoVert *mv2 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v_tri[1]);
MDynTopoVert *mv3 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v_tri[2]);
@@ -3293,7 +3288,7 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
CustomData_bmesh_copy_data(
&pbvh->bm->ldata, &pbvh->bm->ldata, l->prev->head.data, &l2->prev->head.data);
-# if 0
+#if 0
BMLoop *l3 = f2->l_first;
do {
if (l3->v == f2->l_first->v && l3->f != f2 && l3->f != l->f) {
@@ -3302,11 +3297,10 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
break;
}
} while ((l3 = l3->radial_next) != f2->l_first);
-# endif
+#endif
}
}
BM_LOOPS_OF_VERT_ITER_END;
-#endif
// pbvh_bmesh_check_nodes_simple(pbvh);
@@ -3612,6 +3606,8 @@ cleanup_valence_3_4(EdgeQueueContext *ectx,
GSet *vset = BLI_gset_ptr_new("vset");
const int cd_vert_node = pbvh->cd_vert_node_offset;
+ int updateflag = DYNVERT_NEED_BOUNDARY | DYNVERT_NEED_DISK_SORT | DYNVERT_NEED_VALENCE;
+
for (int vi = 0; vi < ectx->val34_verts_tot; vi++) {
BMVert *v = ectx->val34_verts[vi];
const int n = BM_ELEM_CD_GET_INT(v, cd_vert_node);
@@ -3626,6 +3622,8 @@ cleanup_valence_3_4(EdgeQueueContext *ectx,
MDynTopoVert *mv = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v);
+ mv->flag &= ~DYNVERT_VALENCE_TEMP;
+
validate_vert(pbvh->bm, v, false, true);
check_vert_fan_are_tris(pbvh, v);
validate_vert(pbvh->bm, v, true, true);
@@ -3664,6 +3662,17 @@ cleanup_valence_3_4(EdgeQueueContext *ectx,
for (int j = 0; j < val; j++) {
ls[i++] = l->v == v ? l->next : l;
+ MDynTopoVert *mv_l;
+
+ if (l->v == v) {
+ mv_l = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, l->next->v);
+ }
+ else {
+ mv_l = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, l->v);
+ }
+
+ mv_l->flag |= updateflag;
+
l = l->prev->radial_next;
if (l->v != v) {
@@ -3789,13 +3798,17 @@ cleanup_valence_3_4(EdgeQueueContext *ectx,
validate_vert(pbvh->bm, v, false, false);
- BKE_pbvh_bmesh_mark_update_valence(pbvh, (SculptVertRef){.i = (intptr_t)vs[0]});
- BKE_pbvh_bmesh_mark_update_valence(pbvh, (SculptVertRef){.i = (intptr_t)vs[1]});
- BKE_pbvh_bmesh_mark_update_valence(pbvh, (SculptVertRef){.i = (intptr_t)vs[2]});
+ MDynTopoVert *mv1 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, vs[0]);
+ MDynTopoVert *mv2 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, vs[1]);
+ MDynTopoVert *mv3 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, vs[2]);
+
+ mv1->flag |= updateflag;
+ mv2->flag |= updateflag;
+ mv3->flag |= updateflag;
BMFace *f1 = NULL;
bool ok1 = vs[0] != vs[1] && vs[1] != vs[2] && vs[0] != vs[2];
- // ok1 = ok1 && !BM_face_exists(vs, 3);
+ ok1 = ok1 && !BM_face_exists(vs, 3);
if (ok1) {
f1 = pbvh_bmesh_face_create(pbvh, n, vs, NULL, l->f, true, false);
@@ -3810,16 +3823,23 @@ cleanup_valence_3_4(EdgeQueueContext *ectx,
BMFace *f2 = NULL;
- bool ok2 = val == 4 && vs[0] != vs[2] && vs[2] != vs[3] && vs[0] != vs[3];
- // ok2 = ok2 && !BM_face_exists(vs, 3);
- if (ok2) {
+ if (val == 4) {
vs[0] = ls[0]->v;
vs[1] = ls[2]->v;
vs[2] = ls[3]->v;
+ }
- BKE_pbvh_bmesh_mark_update_valence(pbvh, (SculptVertRef){.i = (intptr_t)vs[0]});
- BKE_pbvh_bmesh_mark_update_valence(pbvh, (SculptVertRef){.i = (intptr_t)vs[1]});
- BKE_pbvh_bmesh_mark_update_valence(pbvh, (SculptVertRef){.i = (intptr_t)vs[2]});
+ bool ok2 = val == 4 && vs[0] != vs[2] && vs[2] != vs[3] && vs[0] != vs[3];
+ ok2 = ok2 && !BM_face_exists(vs, 3);
+
+ if (ok2) {
+ MDynTopoVert *mv1 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, vs[0]);
+ MDynTopoVert *mv2 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, vs[1]);
+ MDynTopoVert *mv3 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, vs[2]);
+
+ mv1->flag |= updateflag;
+ mv2->flag |= updateflag;
+ mv3->flag |= updateflag;
BMFace *example = NULL;
if (v->e && v->e->l) {
@@ -3874,6 +3894,128 @@ cleanup_valence_3_4(EdgeQueueContext *ectx,
return modified;
}
+//#define DEFRAGMENT_MEMORY
+bool BM_defragment_vertex(BMesh *bm,
+ BMVert *v,
+ RNG *rand,
+ void (*on_vert_swap)(BMVert *a, BMVert *b, void *userdata),
+ void *userdata);
+
+typedef struct SwapData {
+ PBVH *pbvh;
+} SwapData;
+
+static void on_vert_swap(BMVert *v1, BMVert *v2, void *userdata)
+{
+ SwapData *sdata = (SwapData *)userdata;
+ PBVH *pbvh = sdata->pbvh;
+ BMesh *bm = pbvh->bm;
+
+ int ni1 = BM_ELEM_CD_GET_INT(v1, pbvh->cd_vert_node_offset);
+ int ni2 = BM_ELEM_CD_GET_INT(v2, pbvh->cd_vert_node_offset);
+
+ // check we don't have an orphan vert
+ PBVHNode *node1 = v1->e && v1->e->l && ni1 >= 0 ? pbvh->nodes + ni1 : NULL;
+ PBVHNode *node2 = v2->e && v2->e->l && ni2 >= 0 ? pbvh->nodes + ni2 : NULL;
+
+ if ((node1 && !(node1->flag & PBVH_Leaf)) || (node2 && !(node2->flag & PBVH_Leaf))) {
+ printf("node error! %s\n", __func__);
+ }
+
+ int updateflag = PBVH_UpdateOtherVerts | PBVH_UpdateNormals | PBVH_UpdateTris | PBVH_UpdateTris;
+ updateflag |= PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw |
+ PBVH_RebuildDrawBuffers | PBVH_UpdateVisibility;
+ updateflag |= PBVH_UpdateDrawBuffers;
+
+ if (node1) {
+ node1->flag |= updateflag;
+ BLI_table_gset_remove(node1->bm_unique_verts, v1, NULL);
+ BLI_table_gset_insert(node1->bm_unique_verts, v2);
+ }
+
+ if (node2) {
+ node2->flag |= updateflag;
+ BLI_table_gset_remove(node2->bm_unique_verts, v2, NULL);
+ BLI_table_gset_insert(node2->bm_unique_verts, v1);
+ }
+
+ if (!node1 || !node2) {
+ // eek!
+ printf("swap pbvh error! %s %d %d\n", __func__, ni1, ni2);
+ return;
+ }
+}
+
+static unsigned int rseed = 0;
+static bool do_cleanup_3_4(EdgeQueueContext *eq_ctx,
+ PBVH *pbvh,
+ const float center[3],
+ const float view_normal[3],
+ float radius,
+ bool use_frontface,
+ bool use_projected)
+{
+ EdgeQueue q;
+
+ bool modified = false;
+
+ eq_ctx->q = &q;
+ edge_queue_init(eq_ctx, use_projected, use_frontface, center, view_normal, radius);
+
+ for (int n = 0; n < pbvh->totnode; n++) {
+ PBVHNode *node = pbvh->nodes + n;
+ BMVert *v;
+
+ if (!(node->flag & PBVH_Leaf) || !(node->flag & PBVH_UpdateTopology)) {
+ continue;
+ }
+
+ TGSET_ITER (v, node->bm_unique_verts) {
+ if (!eq_ctx->q->edge_queue_vert_in_range(eq_ctx->q, v)) {
+ continue;
+ }
+
+ if (use_frontface && dot_v3v3(v->no, view_normal) < 0.0f) {
+ continue;
+ }
+
+ MDynTopoVert *mv = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v);
+
+ if (mv->flag & DYNVERT_NEED_VALENCE) {
+ BKE_pbvh_bmesh_update_valence(pbvh->cd_dyn_vert, (SculptVertRef){.i = (intptr_t)v});
+ }
+
+ if (mv->valence < 5) {
+ edge_queue_insert_val34_vert(eq_ctx, v);
+ }
+ }
+ TGSET_ITER_END;
+ }
+
+ BM_log_entry_add_ex(pbvh->bm, pbvh->bm_log, true);
+
+ pbvh_bmesh_check_nodes(pbvh);
+
+ // untag val34 verts
+ for (int i = 0; i < eq_ctx->val34_verts_tot; i++) {
+ BMVert *v = eq_ctx->val34_verts[i];
+
+ if (!v || v->head.htype != BM_VERT || !v->head.data) {
+ printf("%s error\n", __func__);
+ continue;
+ }
+ MDynTopoVert *mv = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v);
+
+ mv->flag &= ~DYNVERT_VALENCE_TEMP;
+ }
+
+ modified |= cleanup_valence_3_4(
+ eq_ctx, pbvh, center, view_normal, radius, use_frontface, use_projected);
+ pbvh_bmesh_check_nodes(pbvh);
+
+ return modified;
+}
+
/* Collapse short edges, subdivide long edges */
bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
PBVHTopologyUpdateMode mode,
@@ -3887,15 +4029,6 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
DyntopoMaskCB mask_cb,
void *mask_cb_data)
{
- /*
- if (sym_axis >= 0 &&
- PIL_check_seconds_timer() - last_update_time[sym_axis] < DYNTOPO_RUN_INTERVAL) {
- return false;
- }
-
- if (sym_axis >= 0) {
- last_update_time[sym_axis] = PIL_check_seconds_timer();
- }*/
/* 2 is enough for edge faces - manifold edge */
BLI_buffer_declare_static(BMLoop *, edge_loops, BLI_BUFFER_NOP, 2);
@@ -3943,29 +4076,65 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
printf("v: %.2f e: %.2f l: %.2f f: %.2f\n", fvmem, femem, flmem, ffmem);
}
+
+ float safe_smooth;
+
+ if ((mode & PBVH_Subdivide) && (!(mode & PBVH_Collapse) || (mode & PBVH_LocalCollapse))) {
+ safe_smooth = DYNTOPO_SAFE_SMOOTH_SUBD_ONLY_FAC;
+ }
+ else {
+ safe_smooth = DYNTOPO_SAFE_SMOOTH_FAC;
+ }
+
#endif
- EdgeQueueContext eq_ctx = {NULL,
- NULL,
- pbvh->bm,
- mask_cb,
- mask_cb_data,
-
- cd_dyn_vert,
- cd_vert_mask_offset,
- cd_vert_node_offset,
- cd_face_node_offset,
+ /*
+
+
+typedef struct EdgeQueueContext {
+ EdgeQueue *q;
+ BLI_mempool *pool;
+ BMesh *bm;
+ DyntopoMaskCB mask_cb;
+ void *mask_cb_data;
+ int cd_dyn_vert;
+ int cd_vert_mask_offset;
+ int cd_vert_node_offset;
+ int cd_face_node_offset;
+ float avg_elen;
+ float max_elen;
+ float min_elen;
+ float totedge;
+ BMVert **val34_verts;
+ int val34_verts_tot;
+ int val34_verts_size;
+ bool local_mode;
+ float surface_smooth_fac;
+} EdgeQueueContext;
+*/
+ EdgeQueueContext eq_ctx = {.q = NULL,
+ .pool = NULL,
+ .bm = pbvh->bm,
+ .mask_cb = mask_cb,
+ .mask_cb_data = mask_cb_data,
+
+ .cd_dyn_vert = cd_dyn_vert,
+ .cd_vert_mask_offset = cd_vert_mask_offset,
+ .cd_vert_node_offset = cd_vert_node_offset,
+ .cd_face_node_offset = cd_face_node_offset,
.avg_elen = 0.0f,
.max_elen = -1e17,
.min_elen = 1e17,
.totedge = 0.0f,
- NULL,
- 0,
- 0,
- false};
+ .val34_verts = NULL,
+ .val34_verts_tot = 0,
+ .val34_verts_size = 0,
+ .local_mode = false,
+ .surface_smooth_fac = safe_smooth};
int tempflag = 1 << 15;
#if 1
+
if (mode & PBVH_Collapse) {
BM_log_entry_add_ex(pbvh->bm, pbvh->bm_log, true);
@@ -4002,6 +4171,8 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
ratio = MIN2(ratio, 5.0f);
}
}
+# else
+ ratio = 1.0f;
# endif
float brusharea = radius / (pbvh->bm_min_edge_len * 0.5f + pbvh->bm_max_edge_len * 0.5f);
@@ -4022,6 +4193,12 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
BLI_mempool_destroy(queue_pool);
}
+ // if no collapse, run cleanup here to avoid degenerate geometry
+ if ((mode & PBVH_Cleanup) && !(mode & PBVH_Collapse)) {
+ modified |= do_cleanup_3_4(
+ &eq_ctx, pbvh, center, view_normal, radius, use_frontface, use_projected);
+ }
+
if (mode & PBVH_Subdivide) {
BM_log_entry_add_ex(pbvh->bm, pbvh->bm_log, true);
@@ -4040,8 +4217,9 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
use_projected,
mode & PBVH_LocalSubdivide);
-# if 0 /// def SKINNY_EDGE_FIX
- // prevent remesher thrashing by throttling edge splitting in pathological case of skinny edges
+# ifdef SKINNY_EDGE_FIX
+ // prevent remesher thrashing by throttling edge splitting in pathological case of skinny
+ // edges
float avg_elen = eq_ctx.avg_elen;
if (eq_ctx.totedge > 0.0f) {
avg_elen /= eq_ctx.totedge;
@@ -4069,7 +4247,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
brusharea = brusharea * brusharea * M_PI;
int max_steps = (int)((float)DYNTOPO_MAX_ITER * ratio);
- max_steps = (int)(brusharea * ratio * 1.0f);
+ max_steps = (int)(brusharea * ratio * 2.0f);
printf("brusharea: %.2f, ratio: %.2f\n", brusharea, ratio);
printf("subdivide max_steps %d\n", max_steps);
@@ -4088,63 +4266,48 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
#endif
- /* eq_ctx.val34_verts is build in long_edge_queue_create, if it's
- disabled we have to build it manually
- */
- if ((mode & PBVH_Cleanup) && !(mode & PBVH_Subdivide)) {
- EdgeQueue q;
+ // if have collapse, run cleanup for nicer geometry more compatible with topology rake
+ if ((mode & PBVH_Cleanup) && (mode & PBVH_Collapse)) {
+ modified |= do_cleanup_3_4(
+ &eq_ctx, pbvh, center, view_normal, radius, use_frontface, use_projected);
+ }
- eq_ctx.q = &q;
- edge_queue_init(&eq_ctx, use_projected, use_frontface, center, view_normal, radius);
+ int dcount = 0;
- for (int n = 0; n < pbvh->totnode; n++) {
- PBVHNode *node = pbvh->nodes + n;
+//#define DEFRAGMENT_MEMORY
+#ifdef DEFRAGMENT_MEMORY
+ RNG *rng = BLI_rng_new(rseed++);
+ SwapData swapdata = {.pbvh = pbvh};
+ for (int n = 0; n < pbvh->totnode; n++) {
+ PBVHNode *node = pbvh->nodes + n;
- if (!(node->flag & PBVH_Leaf) || !(node->flag & PBVH_UpdateTopology)) {
- continue;
- }
+ if (!(node->flag & PBVH_Leaf) || !(node->flag & PBVH_UpdateTopology)) {
+ continue;
+ }
- BMVert *v;
- TGSET_ITER (v, node->bm_unique_verts) {
- if (!eq_ctx.q->edge_queue_vert_in_range(eq_ctx.q, v)) {
- continue;
- }
+ BMVert *v;
- if (use_frontface && dot_v3v3(v->no, view_normal) < 0.0f) {
- continue;
- }
+ float radius_sqr = radius * radius;
- MDynTopoVert *mv = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v);
+ TGSET_ITER (v, node->bm_unique_verts) {
+ if (len_squared_v3v3(v->co, center) > radius_sqr) {
+ continue;
+ }
- if (mv->flag & DYNVERT_NEED_VALENCE) {
- BKE_pbvh_bmesh_update_valence(pbvh->cd_dyn_vert, (SculptVertRef){.i = (intptr_t)v});
- }
+ if (BM_defragment_vertex(pbvh->bm, v, rng, on_vert_swap, &swapdata)) {
+ modified = true;
+ dcount++;
+ }
- if (mv->valence < 5) {
- edge_queue_insert_val34_vert(&eq_ctx, v);
- }
+ if (dcount > 100) {
+ // break;
}
- TGSET_ITER_END;
}
+ TGSET_ITER_END;
}
- // untag val34 verts
- for (int i = 0; i < eq_ctx.val34_verts_tot; i++) {
- BMVert *v = eq_ctx.val34_verts[i];
- MDynTopoVert *mv = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v);
-
- mv->flag &= ~DYNVERT_VALENCE_TEMP;
- }
-
- if (mode & PBVH_Cleanup) {
- BM_log_entry_add_ex(pbvh->bm, pbvh->bm_log, true);
-
- pbvh_bmesh_check_nodes(pbvh);
-
- modified |= cleanup_valence_3_4(
- &eq_ctx, pbvh, center, view_normal, radius, use_frontface, use_projected);
- pbvh_bmesh_check_nodes(pbvh);
- }
+ BLI_rng_free(rng);
+#endif
if (modified) {
@@ -4202,7 +4365,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
PBVHNode *node = pbvh->nodes + i;
if (node->flag & PBVH_Leaf) {
- BKE_pbvh_bmesh_check_tris(pbvh, node);
+ // BKE_pbvh_bmesh_check_tris(pbvh, node);
}
}
@@ -4325,14 +4488,58 @@ static const int splitmap[43][16] = {
{6, -1, 3, -1, 5, -1, 1, -1}, // 42
};
-static void pbvh_split_edges(
- PBVH *pbvh, BMesh *bm, BMEdge **edges, int totedge, bool ignore_isolated_edges)
+static void pbvh_split_edges(EdgeQueueContext *eq_ctx,
+ PBVH *pbvh,
+ BMesh *bm,
+ BMEdge **edges1,
+ int totedge,
+ bool ignore_isolated_edges)
{
+ BMEdge **edges = edges1;
BMFace **faces = NULL;
BLI_array_staticdeclare(faces, 512);
bm_log_message(" == split edges == ");
+//# define EXPAND_SPLIT_REGION
+# ifdef EXPAND_SPLIT_REGION
+ BLI_array_declare(edges);
+
+ edges = MEM_callocN(sizeof(void *) * totedge, "edges copy");
+ memcpy(edges, edges1, sizeof(void *) * totedge);
+
+ BLI_array_len_set(edges, totedge);
+
+ GSet *visit = BLI_gset_ptr_new("visit");
+ for (int i = 0; i < totedge; i++) {
+ BLI_gset_add(visit, edges[i]);
+ }
+
+ for (int i = 0; i < totedge; i++) {
+ BMEdge *e = edges[i];
+ BMLoop *l = e->l;
+
+ if (!l) {
+ continue;
+ }
+
+ do {
+ BMLoop *l2 = l->f->l_first;
+ do {
+ if (!BLI_gset_haskey(visit, l2->e)) {
+ // BLI_gset()
+ BLI_gset_add(visit, l2->e);
+ l2->e->head.hflag |= SPLIT_TAG;
+ BLI_array_append(edges, l2->e);
+ }
+ } while ((l2 = l2->next) != l->f->l_first);
+ } while ((l = l->radial_next) != e->l);
+ }
+
+ BLI_gset_free(visit, NULL);
+ totedge = BLI_array_len(edges);
+# endif
+
const int node_updateflag = PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateNormals |
PBVH_UpdateOtherVerts | PBVH_UpdateCurvatureDir |
PBVH_UpdateTriAreas | PBVH_UpdateDrawBuffers |
@@ -4510,7 +4717,9 @@ static void pbvh_split_edges(
mv->flag |= DYNVERT_NEED_VALENCE | DYNVERT_NEED_BOUNDARY | DYNVERT_NEED_DISK_SORT;
mv->stroke_id = pbvh->stroke_id;
-# if 1
+ mv->flag |= DYNVERT_NEED_DISK_SORT | DYNVERT_NEED_VALENCE | DYNVERT_NEED_BOUNDARY;
+ mv->flag &= ~DYNVERT_VALENCE_TEMP;
+
BM_ELEM_CD_SET_INT(newv, pbvh->cd_vert_node_offset, DYNTOPO_NODE_NONE);
int ni = BM_ELEM_CD_GET_INT(v1, pbvh->cd_vert_node_offset);
@@ -4578,10 +4787,6 @@ static void pbvh_split_edges(
BM_ELEM_CD_SET_INT(newv, pbvh->cd_vert_node_offset, DYNTOPO_NODE_NONE);
printf("eek!");
}
-
-# else
- BM_ELEM_CD_SET_INT(newv, pbvh->cd_vert_node_offset, DYNTOPO_NODE_NONE);
-# endif
}
bm_log_message(" == split edges (triangulate) == ");
@@ -4721,5 +4926,10 @@ static void pbvh_split_edges(
}
BLI_array_free(faces);
+# ifdef EXPAND_SPLIT_REGION
+ if (edges != edges1) {
+ BLI_array_free(edges);
+ }
+# endif
}
#endif
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 078c087a1b5..7d9e3fc4c74 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -1948,9 +1948,12 @@ void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene)
sd->detail_size = 12;
}
+ if (!sd->detail_range || !sd->dyntopo_spacing) {
+ sd->flags |= SCULPT_DYNTOPO_CLEANUP; // should really do this in do_versions_290.c
+ }
+
if (!sd->detail_range) {
sd->detail_range = 0.4f;
- sd->flags |= SCULPT_DYNTOPO_CLEANUP; // should really do this in do_versions_290.c
}
if (!sd->detail_percent) {
@@ -1958,7 +1961,7 @@ void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene)
}
if (!sd->dyntopo_spacing) {
- sd->dyntopo_spacing = 25;
+ sd->dyntopo_spacing = 35;
}
if (sd->constant_detail == 0.0f) {
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index cb580ff4606..11f9ae7a616 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -2193,9 +2193,21 @@ bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
continue;
}
+#ifdef SCULPT_DIAGONAL_EDGE_MARKS
+ int ecount = 0;
+#endif
+
// clear edgeflag for building edge indices later
BMLoop *l = f->l_first;
do {
+#ifdef SCULPT_DIAGONAL_EDGE_MARKS
+ BMEdge *e2 = l->v->e;
+ do {
+ if (e2->head.hflag & BM_ELEM_DRAW) {
+ ecount++;
+ }
+ } while ((e2 = BM_DISK_EDGE_NEXT(e2, l->v)) != l->v->e);
+#endif
l->e->head.hflag &= ~edgeflag;
} while ((l = l->next) != f->l_first);
@@ -2235,8 +2247,13 @@ bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
BMLoop *l2 = loops[loops_idx[i][(j + 1) % 3]];
void **val = NULL;
+ BMEdge *e = BM_edge_exists(l->v, l2->v);
- if (BM_edge_exists(l->v, l2->v)) {
+# ifdef SCULPT_DIAGONAL_EDGE_MARKS
+ if (e && (e->head.hflag & BM_ELEM_DRAW)) {
+# else
+ if (e) {
+# endif
tri->eflag |= 1 << j;
mat_tri->eflag |= 1 << j;
}
@@ -3609,20 +3626,27 @@ BMesh *BKE_pbvh_reorder_bmesh(PBVH *pbvh)
v = node2->verts[j];
#if 0
+ const int cd_vcol = CustomData_get_offset(&pbvh->bm->vdata, CD_PROP_COLOR);
+
if (cd_vcol >= 0) {
MPropCol *col = BM_ELEM_CD_GET_VOID_P(node2->verts[j], cd_vcol);
float r = 0.0f, g = 0.0f, b = 0.0f;
+ ReVertNode *parent = node2->parent;
+ for (int j = 0; parent->parent && j < 2; j++) {
+ parent = parent->parent;
+ }
+
unsigned int p = (unsigned int)node2->parent;
p = p % 65535;
- unsigned int p2 = (unsigned int)node2->parent;
+ unsigned int p2 = (unsigned int)parent;
p2 = p2 % 65535;
r = ((float)vorder) * 0.01;
g = ((float)p2) / 65535.0f;
- b = ((float)p) / 65535.0f;
+ b = ((float)p2) / 65535.0f;
r = cosf(r * 17.2343) * 0.5 + 0.5;
g = cosf(g * 11.2343) * 0.5 + 0.5;
diff --git a/source/blender/blenlib/BLI_mempool.h b/source/blender/blenlib/BLI_mempool.h
index b8e1a22b875..4093b9b5fe0 100644
--- a/source/blender/blenlib/BLI_mempool.h
+++ b/source/blender/blenlib/BLI_mempool.h
@@ -87,6 +87,10 @@ enum {
* order of allocation when no chunks have been freed.
*/
BLI_MEMPOOL_ALLOW_ITER = (1 << 0),
+
+ /* allow random access, implies BLI_MEMPOOL_ALLOW_ITER since we
+ need the freewords to detect free state of elements*/
+ BLI_MEMPOOL_RANDOM_ACCESS = (1 << 1) | (1 << 0)
};
void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter) ATTR_NONNULL();
@@ -105,6 +109,13 @@ BLI_mempool *BLI_mempool_create_for_tasks(const unsigned int esize,
int *r_esize,
int flag);
+// memory coherence stuff
+int BLI_mempool_find_elems_fuzzy(
+ BLI_mempool *pool, int idx, int range, void **r_elems, int r_elems_size);
+
+int BLI_mempool_get_size(BLI_mempool *pool);
+int BLI_mempool_find_real_index(BLI_mempool *pool, void *ptr);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/intern/BLI_mempool.c b/source/blender/blenlib/intern/BLI_mempool.c
index 65ebf38debf..a8e7a1e0ec2 100644
--- a/source/blender/blenlib/intern/BLI_mempool.c
+++ b/source/blender/blenlib/intern/BLI_mempool.c
@@ -124,6 +124,12 @@ struct BLI_mempool {
* this is needed for iteration so we can loop over chunks in the order added. */
BLI_mempool_chunk *chunk_tail;
+ /* only used if BLI_MEMPOOL_RANDOM_ACCESS is true*/
+ BLI_mempool_chunk **chunktable;
+
+ /* only used if BLI_MEMPOOL_RANDOM_ACCESS is true*/
+ int totchunk;
+
/** Element size in bytes. */
uint esize;
/** Chunk size in bytes. */
@@ -168,6 +174,33 @@ static uint power_of_2_max_u(uint x)
}
#endif
+static void mempool_update_chunktable(BLI_mempool *pool)
+{
+ if (!(pool->flag & BLI_MEMPOOL_RANDOM_ACCESS)) {
+ return;
+ }
+
+ pool->totchunk = 0;
+ BLI_mempool_chunk *chunk = pool->chunks;
+
+ while (chunk) {
+ pool->totchunk++;
+ chunk = chunk->next;
+ }
+
+ MEM_SAFE_FREE(pool->chunktable);
+ pool->chunktable = (BLI_mempool_chunk **)MEM_mallocN(
+ sizeof(pool->chunktable) * (size_t)pool->totchunk, "mempool chunktable");
+
+ int i = 0;
+ chunk = pool->chunks;
+
+ while (chunk) {
+ pool->chunktable[i++] = chunk;
+ chunk = chunk->next;
+ }
+}
+
BLI_INLINE BLI_mempool_chunk *mempool_chunk_find(BLI_mempool_chunk *head, uint index)
{
while (index-- && head) {
@@ -209,6 +242,26 @@ static BLI_freenode *mempool_chunk_add(BLI_mempool *pool,
BLI_freenode *curnode = CHUNK_DATA(mpchunk);
uint j;
+ if (pool->flag & BLI_MEMPOOL_RANDOM_ACCESS) {
+ if (!pool->chunktable ||
+ MEM_allocN_len(pool->chunktable) / sizeof(void *) <= (size_t)pool->totchunk) {
+ void *old = pool->chunktable;
+
+ size_t size = (size_t)pool->totchunk + 2ULL;
+ size += size >> 1ULL;
+
+ pool->chunktable = MEM_mallocN(sizeof(void *) * size, "mempool chunktable");
+
+ if (old) {
+ memcpy(pool->chunktable, old, sizeof(void *) * (size_t)pool->totchunk);
+ }
+
+ MEM_SAFE_FREE(old);
+ }
+
+ pool->chunktable[pool->totchunk++] = mpchunk;
+ }
+
/* append */
if (pool->chunk_tail) {
pool->chunk_tail->next = mpchunk;
@@ -406,6 +459,9 @@ BLI_mempool *BLI_mempool_create(uint esize, uint totelem, uint pchunk, uint flag
/* allocate the pool structure */
pool = MEM_mallocN(sizeof(BLI_mempool), "memory pool");
+ pool->totchunk = 0;
+ pool->chunktable = NULL;
+
/* set the elem size */
if (esize < (int)MEMPOOL_ELEM_SIZE_MIN) {
esize = (int)MEMPOOL_ELEM_SIZE_MIN;
@@ -502,6 +558,84 @@ void *BLI_mempool_calloc(BLI_mempool *pool)
return retval;
}
+int BLI_mempool_find_real_index(BLI_mempool *pool, void *ptr)
+{
+ BLI_mempool_chunk *chunk = pool->chunks;
+ uintptr_t uptr = ptr;
+ uintptr_t cptr;
+ int chunki = 0;
+
+ while (chunk) {
+ cptr = (uintptr_t)chunk;
+
+ if (uptr >= cptr && uptr < cptr + pool->csize) {
+ break;
+ }
+
+ chunk = chunk->next;
+ chunki++;
+ }
+
+ if (!chunk) {
+ return -1; // failed
+ }
+
+ return chunki * (int)pool->pchunk + ((int)(uptr - cptr)) / (int)pool->esize;
+}
+
+/*finds an element in pool that's roughly at idx, idx*/
+int BLI_mempool_find_elems_fuzzy(
+ BLI_mempool *pool, int idx, int range, void **r_elems, int r_elems_size)
+{
+ int istart = idx - range, iend = idx + range;
+ istart = MAX2(istart, 0);
+
+ int totelem = 0;
+
+ for (int i = istart; i < iend; i++) {
+ int chunki = i / (int)pool->pchunk;
+ if (chunki >= (int)pool->totchunk) {
+ break;
+ }
+
+ int idx2 = i % (int)pool->pchunk;
+
+ BLI_mempool_chunk *chunk = pool->chunktable[chunki];
+ char *data = (char *)CHUNK_DATA(chunk);
+ void *ptr = data + idx2 * (int)pool->esize;
+
+ BLI_asan_unpoison(ptr, pool->esize);
+
+ BLI_freenode *fnode = (BLI_freenode *)ptr;
+ if (fnode->freeword == FREEWORD) {
+ BLI_asan_poison(ptr, pool->esize);
+ continue;
+ }
+
+ r_elems[totelem++] = ptr;
+
+ if (totelem == r_elems_size) {
+ break;
+ }
+ }
+
+ return totelem;
+}
+
+int BLI_mempool_get_size(BLI_mempool *pool)
+{
+ BLI_mempool_chunk *chunk = pool->chunks;
+ int ret = 0;
+
+ while (chunk) {
+ chunk = chunk->next;
+
+ ret += pool->pchunk;
+ }
+
+ return ret;
+}
+
/**
* Free an element from the mempool.
*
@@ -563,6 +697,8 @@ void BLI_mempool_free(BLI_mempool *pool, void *addr)
first->next = NULL;
pool->chunk_tail = first;
+ mempool_update_chunktable(pool);
+
#ifdef USE_TOTALLOC
pool->totalloc = pool->pchunk;
#endif
@@ -962,6 +1098,8 @@ void BLI_mempool_destroy(BLI_mempool *pool)
{
mempool_chunk_free_all(pool->chunks, pool);
+ MEM_SAFE_FREE(pool->chunktable);
+
#ifdef WITH_MEM_VALGRIND
VALGRIND_DESTROY_MEMPOOL(pool);
#endif
diff --git a/source/blender/bmesh/intern/bmesh_log.c b/source/blender/bmesh/intern/bmesh_log.c
index a0478010ceb..0458ca5f386 100644
--- a/source/blender/bmesh/intern/bmesh_log.c
+++ b/source/blender/bmesh/intern/bmesh_log.c
@@ -1764,11 +1764,15 @@ static void log_idmap_save(BMesh *bm, BMLog *log, BMLogEntry *entry)
int cd_loop_off = cd_id_offs[2];
int *lmap = idmap->maps[2];
+ bool reported = false;
+
BM_ITER_MESH_INDEX (elem, &iter, bm, iters[i], j) {
int id = BM_ELEM_CD_GET_INT(elem, cd_off);
- if ((BMElem *)BM_ELEM_FROM_ID(bm, id) != elem) {
+ if (!reported && (BMElem *)BM_ELEM_FROM_ID(bm, id) != elem) {
printf("IDMap error for elem type %d\n", elem->head.htype);
+ printf(" further errors suppressed\n");
+ reported = true;
}
map[j] = id;
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index 9169c8fe57d..8220f741fda 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -26,8 +26,10 @@
#include "DNA_scene_types.h"
#include "BLI_alloca.h"
+#include "BLI_array.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLI_rand.h"
#include "BLI_utildefines.h"
#include "BKE_customdata.h"
@@ -140,6 +142,23 @@ void BM_mesh_elem_toolflags_clear(BMesh *bm)
}
}
+// int cdmap[8] = {0, 1, -1, -1, 2, -1, -1, -1, 3};
+
+static void bm_swap_cd_data(int htype, BMesh *bm, CustomData *cd, void *a, void *b)
+{
+ int tot = cd->totsize;
+ // int cd_id = bm->idmap.cd_id_off[htype];
+
+ char *sa = (char *)a;
+ char *sb = (char *)b;
+
+ for (int i = 0; i < tot; i++, sa++, sb++) {
+ char tmp = *sa;
+ *sa = *sb;
+ *sb = tmp;
+ }
+}
+
/**
* \brief BMesh Make Mesh
*
@@ -881,12 +900,6 @@ int BM_mesh_elem_count(BMesh *bm, const char htype)
}
}
-static void swap_block(void *tmp, void *a, void *b, int size)
-{
- memcpy(tmp, b, size);
- memcpy(b, a, size);
- memcpy(a, tmp, size);
-}
/**
* Remaps the vertices, edges and/or faces of the bmesh as indicated by vert/edge/face_idx arrays
* (xxx_idx[org_index] = new_index).
@@ -923,25 +936,18 @@ void BM_mesh_remap(BMesh *bm,
bm, (vert_idx ? BM_VERT : 0) | (edge_idx ? BM_EDGE : 0) | (face_idx ? BM_FACE : 0));
CustomData *cdatas[4] = {&bm->vdata, &bm->edata, &bm->ldata, &bm->pdata};
- void *swap_temps[4];
- for (int i = 0; i < 4; i++) {
- if (cdatas[i]->totsize) {
- swap_temps[i] = MEM_mallocN(cdatas[i]->totsize, "cdata temp");
- }
- else {
- swap_temps[i] = NULL;
- }
- }
+#define DO_SWAP(ci, cdata, v, vp) *(v) = *(vp);
-#define DO_SWAP(ci, cdata, v, vp) \
- void *cdold = v->head.data; \
+// NOT WORKING
+/* unswaps customdata blocks*/
+#define DO_SWAP2(ci, cdata, v, vp) \
+ void *cdold = (v)->head.data; \
void *cdnew = (vp)->head.data; \
- *v = *(vp); \
- /* swap customdata blocks*/ \
+ *(v) = *(vp); \
if (cdold) { \
- v->head.data = cdold; \
- swap_block(swap_temps[ci], cdold, cdnew, bm->cdata.totsize); \
+ (v)->head.data = cdold; \
+ memcpy(cdold, cdnew, bm->cdata.totsize); \
}
/* Remap Verts */
@@ -981,11 +987,12 @@ void BM_mesh_remap(BMesh *bm,
DO_SWAP(0, vdata, new_vep, ve);
+ BLI_ghash_insert(vptr_map, *vep, new_vep);
#if 0
printf(
"mapping vert from %d to %d (%p/%p to %p)\n", i, *new_idx, *vep, verts_pool[i], new_vep);
#endif
- BLI_ghash_insert(vptr_map, *vep, new_vep);
+
if (cd_vert_pyptr != -1) {
void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)new_vep), cd_vert_pyptr);
*pyptr = pyptrs[*new_idx];
@@ -1373,10 +1380,6 @@ void BM_mesh_remap(BMesh *bm,
}
}
}
-
- for (int i = 0; i < 4; i++) {
- MEM_SAFE_FREE(swap_temps[i]);
- }
}
/**
@@ -1719,4 +1722,405 @@ void BM_mesh_vert_coords_apply_with_mat4(BMesh *bm,
}
}
+void bm_swap_ids(BMesh *bm, BMElem *e1, BMElem *e2)
+{
+ int cd_id = bm->idmap.cd_id_off[e1->head.htype];
+
+ if (cd_id < 0) {
+ return;
+ }
+
+ int id1 = BM_ELEM_CD_GET_INT(e1, cd_id);
+ int id2 = BM_ELEM_CD_GET_INT(e2, cd_id);
+
+ if (bm->idmap.map) {
+ SWAP(BMElem *, bm->idmap.map[id1], bm->idmap.map[id2]);
+ }
+ else if (bm->idmap.ghash) {
+ void **val1, **val2;
+
+ BLI_ghash_ensure_p(bm->idmap.ghash, POINTER_FROM_INT(id1), &val1);
+ BLI_ghash_ensure_p(bm->idmap.ghash, POINTER_FROM_INT(id2), &val2);
+
+ *val1 = (void *)e2;
+ *val2 = (void *)e1;
+ }
+}
+static void bm_swap_elements_post(BMesh *bm, CustomData *cdata, BMElem *e1, BMElem *e2)
+{
+ // unswap customdata pointers
+ SWAP(void *, e1->head.data, e2->head.data);
+
+ // swap contents of customdata instead
+ bm_swap_cd_data(e1->head.htype, bm, cdata, e1->head.data, e2->head.data);
+
+ // unswap index
+ SWAP(int, e1->head.index, e2->head.index);
+
+ bm_swap_ids(bm, e1, e2);
+}
+
+void BM_swap_verts(BMesh *bm, BMVert *v1, BMVert *v2)
+{
+ if (v1 == v2) {
+ return;
+ }
+
+ BMLoop **ls1 = NULL;
+ BLI_array_staticdeclare(ls1, 64);
+ BMLoop **ls2 = NULL;
+ BLI_array_staticdeclare(ls2, 64);
+
+ BMEdge **es1 = NULL;
+ int *sides1 = NULL;
+
+ BLI_array_staticdeclare(es1, 32);
+ BLI_array_staticdeclare(sides1, 32);
+
+ BMEdge **es2 = NULL;
+ int *sides2 = NULL;
+
+ BLI_array_staticdeclare(es2, 32);
+ BLI_array_staticdeclare(sides2, 32);
+
+ for (int i = 0; i < 2; i++) {
+ BMVert *v = i ? v2 : v1;
+ BMVert *v_2 = i ? v1 : v2;
+
+ BMEdge *e = v->e, *starte = e;
+
+ if (!e) {
+ continue;
+ }
+
+ // int count = 0;
+
+ do {
+ // if (count++ > 10000) {
+ // printf("error!\n");
+ // break;
+ // }
+
+ int side = 0;
+ if (e->v1 == v) {
+ side |= 1;
+ }
+
+ if (e->v2 == v) {
+ side |= 2;
+ }
+
+ if (i) {
+ BLI_array_append(es2, e);
+ BLI_array_append(sides2, side);
+ }
+ else {
+ BLI_array_append(es1, e);
+ BLI_array_append(sides1, side);
+ }
+ } while ((e = BM_DISK_EDGE_NEXT(e, v)) != starte);
+ }
+
+ for (int i = 0; i < 2; i++) {
+ BMVert *v = i ? v2 : v1;
+ BMVert *v_2 = i ? v1 : v2;
+
+ BMEdge **es = i ? es2 : es1;
+ BMLoop **ls = i ? ls2 : ls1;
+ int elen = i ? BLI_array_len(es2) : BLI_array_len(es1);
+ int *sides = i ? sides2 : sides1;
+
+ for (int j = 0; j < elen; j++) {
+ BMEdge *e = es[j];
+ int side = sides[j];
+
+ // if (side == 3) {
+ // printf("edge had duplicate verts!\n");
+ //}
+
+ if (side & 1) {
+ e->v1 = v_2;
+ }
+
+ if (side & 2) {
+ e->v2 = v_2;
+ }
+
+#if 1
+ BMLoop *l = e->l;
+ if (l) {
+
+ do {
+ BMLoop *l2 = l;
+
+ do {
+ if (l2->v == v) {
+ if (i) {
+ BLI_array_append(ls2, l2);
+ }
+ else {
+ BLI_array_append(ls1, l2);
+ }
+ }
+ } while ((l2 = l2->next) != l);
+ } while ((l = l->radial_next) != e->l);
+ }
+#endif
+ // e = enext;
+ } // while (e != starte);
+ }
+
+ for (int i = 0; i < 2; i++) {
+ BMVert *v = i ? v2 : v1;
+ BMVert *v_2 = i ? v1 : v2;
+
+ BMLoop **ls = i ? ls2 : ls1;
+
+ int llen = i ? BLI_array_len(ls2) : BLI_array_len(ls1);
+
+ for (int j = 0; j < llen; j++) {
+ ls[j]->v = v_2;
+ }
+ }
+
+ BLI_array_free(ls1);
+ BLI_array_free(ls2);
+ // BMVert tmp = *v1;
+ //*v1 = *v2;
+ //*v2 = tmp;
+
+ SWAP(BMVert, (*v1), (*v2));
+ // swap contents of customdata, don't swap pointers
+ bm_swap_elements_post(bm, &bm->vdata, (BMElem *)v1, (BMElem *)v2);
+
+ bm->elem_table_dirty |= BM_VERT;
+ bm->elem_index_dirty |= BM_VERT;
+
+ BLI_array_free(es1);
+ BLI_array_free(sides1);
+ BLI_array_free(es2);
+ BLI_array_free(sides2);
+}
+
+void BM_swap_edges(BMesh *bm, BMEdge *e1, BMEdge *e2)
+{
+ for (int i = 0; i < 2; i++) {
+ BMEdge *e = i ? e2 : e1;
+ BMEdge *e_2 = i ? e1 : e2;
+
+ for (int j = 0; j < 2; j++) {
+ BMVert *v = j ? e->v2 : e->v1;
+
+ if (v->e == e) {
+ v->e = e_2;
+ }
+ }
+
+ BMLoop *l = e->l;
+ if (l) {
+ do {
+ l->e = e_2;
+ } while ((l = l->radial_next) != e->l);
+ }
+ }
+
+ SWAP(BMEdge, *e1, *e2);
+ // swap contents of customdata, don't swap pointers
+ bm_swap_elements_post(bm, &bm->edata, (BMElem *)e1, (BMElem *)e2);
+}
+
+void BM_swap_loops(BMesh *bm, BMLoop *l1, BMLoop *l2)
+{
+ for (int i = 0; i < 2; i++) {
+ BMLoop *l = i ? l2 : l1;
+ BMLoop *l_2 = i ? l1 : l2;
+
+ l->prev->next = l2;
+ l->next->prev = l2;
+
+ if (l != l->radial_next) {
+ l->radial_next->radial_prev = l2;
+ l->radial_prev->radial_next = l2;
+ }
+
+ if (l == l->e->l) {
+ l->e->l = l2;
+ }
+
+ if (l == l->f->l_first) {
+ l->f->l_first = l2;
+ }
+ }
+
+ // swap contents of customdata, don't swap pointers
+ SWAP(BMLoop, *l1, *l2);
+ // swap contents of customdata, don't swap pointers
+ bm_swap_elements_post(bm, &bm->ldata, (BMElem *)l1, (BMElem *)l2);
+}
+
+// memory coherence defragmentation
+
+#ifndef ABSLL
+# define ABSLL(a) ((a) < 0LL ? -(a) : (a))
+#endif
+
+#define DEFRAG_FLAG BM_ELEM_TAG_ALT
+
+bool BM_defragment_vertex(BMesh *bm,
+ BMVert *v,
+ RNG *rand,
+ void (*on_vert_swap)(BMVert *a, BMVert *b, void *userdata),
+ void *userdata)
+{
+ BMEdge *e = v->e;
+
+ int cd_vcol = CustomData_get_offset(&bm->vdata, CD_PROP_COLOR);
+
+#if 0
+ if (cd_vcol >= 0) {
+ float *color = BM_ELEM_CD_GET_VOID_P(v, cd_vcol);
+ int idx = BLI_mempool_find_real_index(bm->vpool, (void *)v);
+ int size = BLI_mempool_get_size(bm->vpool);
+
+ float f = (float)idx / (float)size / 2.0f;
+
+ color[0] = color[1] = color[2] = f;
+ color[3] = 1.0f;
+ }
+#endif
+
+ return false;
+
+ // return false;
+
+ // BM_mesh_elem_table_ensure(bm, BM_VERT|BM_EDGE|BM_FACE);
+ if (!e) {
+ return false;
+ }
+
+ bool bad = false;
+ int limit = 128;
+
+ int vlimit = sizeof(BMVert *) * limit;
+ int elimit = sizeof(BMEdge *) * limit;
+ int llimit = sizeof(BMLoop *) * limit;
+ int flimit = sizeof(BMFace *) * limit;
+
+ intptr_t iv = (intptr_t)v;
+
+ BMEdge *laste = NULL;
+ do {
+ BMVert *v2 = BM_edge_other_vert(e, v);
+ intptr_t iv2 = (intptr_t)v2;
+ intptr_t ie = (intptr_t)e;
+
+ v2->head.hflag &= DEFRAG_FLAG;
+ e->head.hflag &= ~DEFRAG_FLAG;
+
+ if (ABSLL(iv2 - iv) > vlimit) {
+ bad = true;
+ break;
+ }
+
+ if (laste) {
+ intptr_t ilaste = (intptr_t)laste;
+ if (ABSLL(ilaste - ie) > elimit) {
+ bad = true;
+ break;
+ }
+ }
+
+ BMLoop *l = e->l;
+ if (l) {
+ do {
+ intptr_t il = (intptr_t)l;
+ intptr_t ilnext = (intptr_t)l->next;
+
+ if (ABSLL(il - ilnext) > llimit) {
+ bad = true;
+ break;
+ }
+
+ BMLoop *l2 = l->f->l_first;
+ do {
+ l2->head.hflag &= ~DEFRAG_FLAG;
+ } while ((l2 = l2->next) != l->f->l_first);
+
+ l2->f->head.hflag &= ~DEFRAG_FLAG;
+
+ l = l->radial_next;
+ } while (l != e->l);
+ }
+ laste = e;
+ } while (!bad && (e = BM_DISK_EDGE_NEXT(e, v)) != v->e);
+
+ float prob = 1.0;
+
+ if (!bad || BLI_rng_get_float(rand) > prob) {
+ return false;
+ }
+
+ // find sort candidates
+ // BLI_mempool_find_elems_fuzzy
+
+ int vidx = BLI_mempool_find_real_index(bm->vpool, (void *)v);
+ const int count = 5;
+ BMVert **elems = BLI_array_alloca(elems, count);
+
+ do {
+ BMVert *v2 = BM_edge_other_vert(e, v);
+ int totelem = BLI_mempool_find_elems_fuzzy(bm->vpool, vidx, 4, (void **)elems, count);
+
+ for (int i = 0; i < totelem; i++) {
+ if (elems[i] == v2 || elems[i] == v) {
+ continue;
+ }
+
+ elems[i]->head.hflag &= ~DEFRAG_FLAG;
+ }
+
+ bool ok = false;
+
+ for (int i = 0; i < totelem; i++) {
+ if (elems[i] == v2 || elems[i] == v || (elems[i]->head.hflag & DEFRAG_FLAG)) {
+ continue;
+ }
+
+ if (elems[i]->head.htype != BM_VERT) {
+ printf("ERROR!\n");
+ }
+ // found one
+ v2->head.hflag |= DEFRAG_FLAG;
+ elems[i]->head.hflag |= DEFRAG_FLAG;
+
+ on_vert_swap(v2, elems[i], userdata);
+ BM_swap_verts(bm, v2, elems[i]);
+
+ BMIter iter;
+ BMEdge *et;
+ int f = 0;
+#if 0
+ BM_ITER_ELEM (et, &iter, v2, BM_EDGES_OF_VERT) {
+ printf("an edge %d\n", f++);
+ }
+
+ f = 0;
+ BM_ITER_ELEM (et, &iter, v, BM_EDGES_OF_VERT) {
+ printf("an 1edge %d\n", f++);
+ }
+#endif
+
+ // BM_swap_verts(bm, v2, elems[i]);
+
+ ok = true;
+ break;
+ }
+
+ if (ok) {
+ break;
+ }
+ } while ((e = BM_DISK_EDGE_NEXT(e, v)) != v->e);
+
+ return true;
+}
/** \} */
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index e0cb863aa97..349fce48396 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -1409,30 +1409,22 @@ static void sculpt_vertex_neighbors_get_bmesh(const SculptSession *ss,
return;
}
+ BMEdge *e2 = NULL;
+
do {
BMVert *v2;
- BMEdge *e2;
-
- if (v == e->v1) {
- v2 = e->v2;
- e2 = e->v1_disk_link.next;
- }
- else {
- v2 = e->v1;
- e2 = e->v2_disk_link.next;
- }
+ e2 = BM_DISK_EDGE_NEXT(e, v);
+ v2 = v == e->v1 ? e->v2 : e->v1;
MDynTopoVert *mv = BKE_PBVH_DYNVERT(ss->cd_dyn_vert, v2);
- if (!(mv->flag & DYNVERT_VERT_FSET_HIDDEN)) {
+ if (!(mv->flag & DYNVERT_VERT_FSET_HIDDEN)) { // && (e->head.hflag & BM_ELEM_DRAW)) {
sculpt_vertex_neighbor_add_nocheck(iter,
BKE_pbvh_make_vref((intptr_t)v2),
BKE_pbvh_make_eref((intptr_t)e),
BM_elem_index_get(v2));
}
-
- e = e2;
- } while (e != v->e);
+ } while ((e = e2) != v->e);
if (ss->fake_neighbors.use_fake_neighbors) {
int index = BM_elem_index_get(v);
@@ -4005,6 +3997,11 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
const bool have_bmesh = BKE_pbvh_type(ss->pbvh) == PBVH_BMESH;
+ const bool weighted = ss->cache->brush->flag2 & BRUSH_SMOOTH_USE_AREA_WEIGHT;
+ if (weighted || ss->cache->brush->boundary_smooth_factor > 0.0f) {
+ BKE_pbvh_check_tri_areas(ss->pbvh, data->nodes[n]);
+ }
+
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
@@ -4092,6 +4089,41 @@ static void bmesh_topology_rake(
SCULPT_dyntopo_ensure_templayer(ss, CD_PROP_COLOR, "_rake_temp");
int cd_temp = SCULPT_dyntopo_get_templayer(ss, CD_PROP_COLOR, "_rake_temp");
+#ifdef SCULPT_DIAGONAL_EDGE_MARKS
+ // reset edge flags, single threaded
+ for (int i = 0; i < totnode; i++) {
+ PBVHNode *node = nodes[i];
+ PBVHVertexIter vd;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, brush->falloff_shape);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+
+ BMVert *v = vd.bm_vert;
+ BMEdge *e = v->e;
+
+ if (!e) {
+ continue;
+ }
+
+ do {
+ e->head.hflag |= BM_ELEM_DRAW;
+ } while ((e = BM_DISK_EDGE_NEXT(e, v)) != v->e);
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+#endif
+
+ if (SCULPT_stroke_is_first_brush_step(ss->cache) &&
+ (ss->cache->brush->flag2 & BRUSH_SMOOTH_USE_AREA_WEIGHT)) {
+ BKE_pbvh_update_all_tri_areas(ss->pbvh);
+ }
+
if (brush->flag2 & BRUSH_TOPOLOGY_RAKE_IGNORE_BRUSH_FALLOFF) {
local_brush = *brush;
brush = &local_brush;
@@ -9960,6 +9992,9 @@ static int sculpt_spatial_sort_exec(bContext *C, wmOperator *op)
ss->active_vertex_index.i = 0;
ss->active_face_index.i = 0;
+ BKE_pbvh_free(ss->pbvh);
+ ss->pbvh = NULL;
+
/* Finish undo. */
SCULPT_undo_push_end();
@@ -9971,7 +10006,8 @@ static int sculpt_spatial_sort_exec(bContext *C, wmOperator *op)
}
/* Redraw. */
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, ND_DATA | NC_OBJECT | ND_DRAW, ob);
return OPERATOR_FINISHED;
}
@@ -11552,6 +11588,7 @@ int SCULPT_vertex_valence_get(const struct SculptSession *ss, SculptVertRef vert
int tot = 0;
int mval = -1;
+#if 0
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
BMVert *v = (BMVert *)vertex.i;
MDynTopoVert *mv = BKE_PBVH_DYNVERT(ss->cd_dyn_vert, v);
@@ -11562,10 +11599,17 @@ int SCULPT_vertex_valence_get(const struct SculptSession *ss, SculptVertRef vert
mval = mv->valence;
-#ifdef NDEBUG
- // return mval;
-#endif
+# ifdef NDEBUG
+ return mval;
+# endif
}
+#else
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ BMVert *v = (BMVert *)vertex.i;
+
+ return BM_vert_edge_count(v);
+ }
+#endif
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
tot++;
diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
index c985d7b9e9d..31919b82a82 100644
--- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
@@ -85,8 +85,11 @@
BMesh *SCULPT_dyntopo_empty_bmesh()
{
+ const BMAllocTemplate allocsize = {
+ .totvert = 2048 * 16, .totface = 2048 * 16, .totloop = 4196 * 16, .totedge = 2048 * 16};
+
BMesh *bm = BM_mesh_create(
- &bm_mesh_allocsize_default,
+ &allocsize,
&((struct BMeshCreateParams){.use_toolflags = false,
.use_unique_ids = true,
.use_id_elem_mask = BM_VERT | BM_EDGE | BM_FACE,
@@ -760,7 +763,8 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene
{
SculptSession *ss = ob->sculpt;
Mesh *me = ob->data;
- const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me);
+ const BMAllocTemplate allocsize = {
+ .totvert = 2048 * 16, .totface = 2048 * 16, .totloop = 4196 * 16, .totedge = 2048 * 16};
SCULPT_pbvh_clear(ob);
@@ -833,6 +837,11 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene
SCULPT_dyntopo_node_layers_update_offsets(ss);
int i = 0;
+ BMEdge *e;
+
+ BM_ITER_MESH (e, &iter, ss->bm, BM_EDGES_OF_MESH) {
+ e->head.hflag |= BM_ELEM_DRAW;
+ }
BM_ITER_MESH (v, &iter, ss->bm, BM_VERTS_OF_MESH) {
MDynTopoVert *mv = BKE_PBVH_DYNVERT(ss->cd_dyn_vert, v);
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c
index 87f14a2a108..72ab985418d 100644
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.c
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c
@@ -77,8 +77,6 @@
static int sculpt_face_material_get(SculptSession *ss, SculptFaceRef face)
{
- int ret = 0;
-
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_BMESH: {
BMFace *f = (BMFace *)face.i;
@@ -94,8 +92,6 @@ static int sculpt_face_material_get(SculptSession *ss, SculptFaceRef face)
int SCULPT_face_set_get(SculptSession *ss, SculptFaceRef face)
{
- int ret = 0;
-
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_BMESH: {
BMFace *f = (BMFace *)face.i;
@@ -268,6 +264,30 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
const int active_fset = abs(ss->cache->paint_face_set);
MVert *mvert = SCULPT_mesh_deformed_mverts_get(ss);
+ const float test_limit = 0.05f;
+ int cd_mask = -1;
+
+ if (ss->bm) {
+ cd_mask = CustomData_get_offset(&ss->bm->vdata, CD_PAINT_MASK);
+ }
+
+ /*check if we need to sample the current face set*/
+
+ bool set_active_faceset = ss->cache->automasking &&
+ (brush->automasking_flags & BRUSH_AUTOMASKING_FACE_SETS);
+ set_active_faceset = set_active_faceset && ss->cache->invert;
+ set_active_faceset = set_active_faceset && ss->cache->automasking->settings.initial_face_set ==
+ ss->cache->automasking->settings.current_face_set;
+
+ int automasking_fset_flag = 0;
+
+ if (set_active_faceset) {
+ // temporarily clear faceset flag
+ automasking_fset_flag = ss->cache->automasking ? ss->cache->automasking->settings.flags &
+ BRUSH_AUTOMASKING_FACE_SETS :
+ 0;
+ ss->cache->automasking->settings.flags &= ~BRUSH_AUTOMASKING_FACE_SETS;
+ }
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
@@ -291,8 +311,60 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
vd.vertex,
thread_id);
- if (fade > 0.05f && ss->face_sets[vert_map->indices[j]] > 0) {
- ss->face_sets[vert_map->indices[j]] = abs(ss->cache->paint_face_set);
+ if (fade > test_limit && ss->face_sets[vert_map->indices[j]] > 0) {
+ bool ok = true;
+
+ int fset = abs(ss->face_sets[vert_map->indices[j]]);
+
+ // XXX kind of hackish, tries to sample faces that are within
+ // 8 pixels of the center of the brush, and using a crude linear
+ // scale at that - joeedh
+ if (set_active_faceset &&
+ fset != abs(ss->cache->automasking->settings.initial_face_set)) {
+
+ float radius = ss->cache->radius;
+ float pixels = 8; // TODO: multiply with DPI
+ radius = pixels * (radius / (float)ss->cache->dyntopo_pixel_radius);
+
+ if (sqrtf(test.dist) < radius) {
+ ss->cache->automasking->settings.initial_face_set = abs(fset);
+ set_active_faceset = false;
+ ss->cache->automasking->settings.flags |= BRUSH_AUTOMASKING_FACE_SETS;
+ }
+ else {
+ ok = false;
+ }
+ }
+
+ MLoop *ml = &ss->mloop[p->loopstart];
+
+ for (int i = 0; i < p->totloop; i++, ml++) {
+ MVert *v = &ss->mvert[ml->v];
+ float fno[3];
+
+ normal_short_to_float_v3(fno, v->no);
+ float mask = ss->vmask ? ss->vmask[ml->v] : 0.0f;
+
+ const float fade2 = bstrength *
+ SCULPT_brush_strength_factor(ss,
+ brush,
+ v->co,
+ sqrtf(test.dist),
+ v->no,
+ fno,
+ mask,
+ (SculptVertRef){.i = ml->v},
+ thread_id);
+
+ if (fade2 < test_limit) {
+ ok = false;
+ break;
+ }
+ }
+
+ if (ok) {
+ ss->face_sets[vert_map->indices[j]] = abs(ss->cache->paint_face_set);
+ }
}
}
}
@@ -318,15 +390,60 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
int fset = BM_ELEM_CD_GET_INT(f, ss->cd_faceset_offset);
- if (fade > 0.05f && fset > 0) {
+ if (fade > test_limit && fset > 0) {
BMLoop *l = f->l_first;
+ bool ok = true;
+
+ // XXX kind of hackish, tries to sample faces that are within
+ // 8 pixels of the center of the brush, and using a crude linear
+ // scale at that - joeedh
+ if (set_active_faceset &&
+ abs(fset) != abs(ss->cache->automasking->settings.initial_face_set)) {
+
+ float radius = ss->cache->radius;
+ float pixels = 8; // TODO: multiple with DPI
+ radius = pixels * (radius / (float)ss->cache->dyntopo_pixel_radius);
+
+ if (sqrtf(test.dist) < radius) {
+ ss->cache->automasking->settings.initial_face_set = abs(fset);
+ set_active_faceset = false;
+ ss->cache->automasking->settings.flags |= BRUSH_AUTOMASKING_FACE_SETS;
+ }
+ else {
+ ok = false;
+ }
+ }
+
do {
+ short sno[3];
+ float mask = cd_mask >= 0 ? BM_ELEM_CD_GET_FLOAT(l->v, cd_mask) : 0.0f;
+
+ normal_float_to_short_v3(sno, l->v->no);
+
+ const float fade2 = bstrength * SCULPT_brush_strength_factor(
+ ss,
+ brush,
+ l->v->co,
+ sqrtf(test.dist),
+ sno,
+ l->v->no,
+ mask,
+ (SculptVertRef){.i = (intptr_t)l->v},
+ thread_id);
+
+ if (fade2 < test_limit) {
+ ok = false;
+ break;
+ }
+
MDynTopoVert *mv = BKE_PBVH_DYNVERT(ss->cd_dyn_vert, l->v);
mv->flag |= DYNVERT_NEED_BOUNDARY;
} while ((l = l->next) != f->l_first);
- BM_ELEM_CD_SET_INT(f, ss->cd_faceset_offset, active_fset);
+ if (ok) {
+ BM_ELEM_CD_SET_INT(f, ss->cd_faceset_offset, active_fset);
+ }
}
}
}
@@ -353,6 +470,11 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
}
}
BKE_pbvh_vertex_iter_end;
+
+ // restore automasking flag
+ if (set_active_faceset) {
+ ss->cache->automasking->settings.flags |= automasking_fset_flag;
+ }
}
static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
@@ -419,8 +541,27 @@ void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in
.nodes = nodes,
};
+ bool threaded = true;
+
+ /*for ctrl invert mode we have to set the automasking initial_face_set
+ to the first non-current faceset that is found*/
+ if (SCULPT_stroke_is_first_brush_step(ss->cache)) {
+ if (ss->cache->invert && ss->cache->automasking &&
+ (brush->automasking_flags & BRUSH_AUTOMASKING_FACE_SETS)) {
+ ss->cache->automasking->settings.current_face_set =
+ ss->cache->automasking->settings.initial_face_set;
+ }
+ }
+
+ if (ss->cache->invert && !ss->cache->alt_smooth && ss->cache->automasking &&
+ ss->cache->automasking->settings.initial_face_set ==
+ ss->cache->automasking->settings.current_face_set) {
+ threaded = false;
+ }
+
+ // ctrl-click is single threaded since the tasks will set the initial face set
TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BKE_pbvh_parallel_range_settings(&settings, threaded, totnode);
if (ss->cache->alt_smooth) {
SCULPT_boundary_info_ensure(ob);
for (int i = 0; i < 4; i++) {
@@ -554,10 +695,6 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
}
if (mode == SCULPT_FACE_SET_SELECTION) {
- Mesh *mesh = ob->data;
- BMesh *bm;
- BMFace *f;
- BMIter iter;
const int totface = ss->totfaces;
for (int i = 0; i < totface; i++) {
@@ -861,8 +998,6 @@ static void sculpt_face_sets_init_loop(Object *ob, const int mode)
}
case PBVH_FACES:
case PBVH_GRIDS: {
- int f_i = fref.i;
-
if (fmaps) {
fmap = fmaps[i] + 2;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 119887db551..8adedbd58e5 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -1027,6 +1027,7 @@ typedef struct AutomaskingSettings {
/* Flags from eAutomasking_flag. */
int flags;
int initial_face_set;
+ int current_face_set; // used by faceset draw tool
float concave_factor;
} AutomaskingSettings;
diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c
index ee49ba416c8..e29f222ac35 100644
--- a/source/blender/editors/sculpt_paint/sculpt_smooth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c
@@ -29,7 +29,9 @@
#include "BLI_compiler_attrs.h"
#include "BLI_hash.h"
#include "BLI_math.h"
+#include "BLI_rand.h"
#include "BLI_task.h"
+#include "BLI_threads.h"
#include "DNA_brush_types.h"
#include "DNA_mesh_types.h"
@@ -61,6 +63,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "atomic_ops.h"
#include "bmesh.h"
#ifdef PROXY_ADVANCED
/* clang-format off */
@@ -102,7 +105,7 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
}
const bool weighted = (ss->cache->brush->flag2 & BRUSH_SMOOTH_USE_AREA_WEIGHT) && !is_boundary;
- float *areas;
+ float *areas = NULL;
SculptCornerType ctype = SCULPT_CORNER_MESH | SCULPT_CORNER_SHARP;
if (check_fsets) {
@@ -146,8 +149,19 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
from verts*/
SculptBoundaryType final_boundary = 0;
+
if (ni.has_edge) {
final_boundary = SCULPT_edge_is_boundary(ss, ni.edge, bflag);
+
+#ifdef SCULPT_DIAGONAL_EDGE_MARKS
+ if (ss->bm) {
+ BMEdge *e = (BMEdge *)ni.edge.i;
+ if (!(e->head.hflag & BM_ELEM_DRAW)) {
+ neighbor_count--;
+ continue;
+ }
+ }
+#endif
}
else {
final_boundary = is_boundary & SCULPT_vertex_is_boundary(ss, ni.vertex, bflag);
@@ -162,7 +176,8 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
*/
- bool slide = slide_fset > 0.0f && is_boundary == SCULPT_BOUNDARY_FACE_SET;
+ bool slide = (slide_fset > 0.0f && is_boundary == SCULPT_BOUNDARY_FACE_SET) ||
+ bound_smooth > 0.0f;
slide = slide && !final_boundary;
if (slide) {
@@ -189,7 +204,7 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
ok = true;
}
- if (do_diffuse && bound_scl) {
+ if (do_diffuse && bound_scl && !is_boundary) {
/*
simple boundary inflator using an ad-hoc diffusion-based pseudo-geodesic field
@@ -429,6 +444,16 @@ static void vec_transform(float r_dir2[3], float no[3], int bits)
}
}
+volatile int blehrand = 0;
+static int blehrand_get()
+{
+ int i = blehrand;
+ i = (i * 124325 + 231423322) & 524287;
+
+ blehrand = i;
+ return i;
+}
+
/* For bmesh: Average surrounding verts based on an orthogonality measure.
* Naturally converges to a quad-like structure. */
void SCULPT_bmesh_four_neighbor_average(SculptSession *ss,
@@ -453,6 +478,18 @@ void SCULPT_bmesh_four_neighbor_average(SculptSession *ss,
float dir[3];
float dir3[3] = {0.0f, 0.0f, 0.0f};
+ const bool weighted = (ss->cache->brush->flag2 & BRUSH_SMOOTH_USE_AREA_WEIGHT);
+ float *areas;
+
+ if (weighted) {
+ SculptVertRef vertex = {.i = (intptr_t)v};
+
+ int val = SCULPT_vertex_valence_get(ss, vertex);
+ areas = BLI_array_alloca(areas, val);
+
+ BKE_pbvh_get_vert_face_areas(ss->pbvh, vertex, areas, val);
+ }
+
copy_v3_v3(dir, col);
if (dot_v3v3(dir, dir) == 0.0f) {
@@ -471,12 +508,23 @@ void SCULPT_bmesh_four_neighbor_average(SculptSession *ss,
BMIter eiter;
BMEdge *e;
bool had_bound = false;
+ int area_i = 0;
- BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+ BM_ITER_ELEM_INDEX (e, &eiter, v, BM_EDGES_OF_VERT, area_i) {
BMVert *v_other = (e->v1 == v) ? e->v2 : e->v1;
float dir2[3];
float *col2 = BM_ELEM_CD_GET_VOID_P(v_other, cd_temp);
+
+ float bucketw = 1.0f; // col2[3] < col[3] ? 2.0f : 1.0f;
+ // bucketw /= 0.00001f + len_v3v3(e->v1->co, e->v2->co);
+ // if (weighted) {
+ // bucketw = 1.0 / (0.000001 + areas[area_i]);
+ //}
+ // if (e == v->e) {
+ // bucketw *= 2.0;
+ //}
+
MDynTopoVert *mv2 = BKE_PBVH_DYNVERT(cd_dyn_vert, v_other);
// bool bound = (mv2->flag &
// (DYNVERT_BOUNDARY)); // | DYNVERT_FSET_BOUNDARY | DYNVERT_SHARP_BOUNDARY));
@@ -506,7 +554,7 @@ void SCULPT_bmesh_four_neighbor_average(SculptSession *ss,
}
}
- closest_vec_to_perp(dir, dir2, v->no, buckets, 1.0f); // col2[3]);
+ closest_vec_to_perp(dir, dir2, v->no, buckets, bucketw); // col2[3]);
madd_v3_v3fl(dir3, dir2, dirw);
totdir3 += dirw;
@@ -525,8 +573,31 @@ void SCULPT_bmesh_four_neighbor_average(SculptSession *ss,
/* fac is a measure of how orthogonal or parallel the edge is
* relative to the direction. */
float fac = dot_v3v3(vec, dir);
+#ifdef SCULPT_DIAGONAL_EDGE_MARKS
+ float th = fabsf(saacos(fac)) / M_PI + 0.5f;
+ th -= floorf(th);
+
+ const float limit = 0.045;
+
+ if (fabsf(th - 0.25) < limit || fabsf(th - 0.75) < limit) {
+ BMEdge enew = *e, eold = *e;
+
+ enew.head.hflag &= ~BM_ELEM_DRAW;
+ // enew.head.hflag |= BM_ELEM_SEAM; // XXX debug
+
+ atomic_cas_int64((intptr_t *)(&e->head.index),
+ *(intptr_t *)(&eold.head.index),
+ *(intptr_t *)(&enew.head.index));
+ }
+#endif
+
fac = fac * fac - 0.5f;
fac *= fac;
+
+ if (weighted) {
+ fac *= areas[area_i];
+ }
+
madd_v3_v3fl(avg_co, v_other->co, fac);
tot_co += fac;
}
@@ -574,9 +645,9 @@ void SCULPT_bmesh_four_neighbor_average(SculptSession *ss,
}
}
- negate_v3(col);
+ // negate_v3(col);
vec_transform(col, v->no, bi);
- negate_v3(col);
+ // negate_v3(col);
}
}