Sculpt dyntopo
* Wrote a simple fix for drawing face sets in inverse (ctrl) mode with face set automasking on. * Various fixes related to hard edges and smoothing. * Started writing some code to defragment bmesh mempools. Need to figure out how to avoid triggering excessive PBVH node rebuilds.
This commit is contained in:
parent
baa24243a5
commit
8bfbbc467a
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
||||
// if (BM_vert_edge_count(v1) == 4 || BM_vert_edge_count(v2) == 4) {
|
||||
// l *= 0.25f;
|
||||
//}
|
||||
val -= 6.0f;
|
||||
val = MAX2(val, 1.0f);
|
||||
|
||||
// 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);
|
||||
}
|
||||
#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,
|
||||
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
|
||||
/*
|
||||
|
||||
|
||||
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)) {
|
||||
if (!(node->flag & PBVH_Leaf) || !(node->flag & PBVH_UpdateTopology)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BMVert *v;
|
||||
|
||||
float radius_sqr = radius * radius;
|
||||
|
||||
TGSET_ITER (v, node->bm_unique_verts) {
|
||||
if (len_squared_v3v3(v->co, center) > radius_sqr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BMVert *v;
|
||||
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);
|
||||
}
|
||||
if (BM_defragment_vertex(pbvh->bm, v, rng, on_vert_swap, &swapdata)) {
|
||||
modified = true;
|
||||
dcount++;
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
/** \} */
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue