diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index 5c73f4e3ca1..7b33a6077d0 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -605,6 +605,8 @@ void CustomData_blend_read(struct BlendDataReader *reader, struct CustomData *da void CustomData_unmark_temporary_nocopy(struct CustomData *data); void CustomData_mark_temporary_nocopy(struct CustomData *data); +int CustomData_get_elem_size(CustomDataLayer *layer); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 301e9ed9422..a6b4f3ab49b 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -27,6 +27,7 @@ #include "BLI_bitmap.h" #include "BLI_utildefines.h" #include "DNA_brush_enums.h" +#include "DNA_customdata_types.h" #include "DNA_object_enums.h" #ifdef __cplusplus @@ -471,6 +472,12 @@ typedef struct SculptSession { struct MPoly *mpoly; struct MLoop *mloop; + // only assigned in PBVH_FACES and PBVH_GRIDS + CustomData *vdata, *edata, *ldata, *pdata; + + // for grids + CustomData temp_vdata, temp_pdata; + /* These contain the vertex and poly counts of the final mesh. */ int totvert, totpoly; diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 3e3e5ca39af..1c5792461ca 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -2107,6 +2107,11 @@ static const LayerTypeInfo *layerType_getInfo(int type) return &LAYERTYPEINFO[type]; } +int CustomData_get_elem_size(CustomDataLayer *layer) +{ + return layerType_getInfo(layer->type)->size; +} + static const char *layerType_getName(int type) { if (type < 0 || type >= CD_NUMTYPES) { diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 80467bef5f2..2c830e92142 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -1630,7 +1630,7 @@ static void sculpt_update_object(Depsgraph *depsgraph, Scene *scene = DEG_get_input_scene(depsgraph); Sculpt *sd = scene->toolsettings->sculpt; SculptSession *ss = ob->sculpt; - const Mesh *me = BKE_object_get_original_mesh(ob); + Mesh *me = BKE_object_get_original_mesh(ob); MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); const bool use_face_sets = (ob->mode & OB_MODE_SCULPT) != 0; @@ -1683,6 +1683,11 @@ static void sculpt_update_object(Depsgraph *depsgraph, ss->multires.level = 0; ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK); ss->vcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR); + + ss->vdata = &me->vdata; + ss->edata = &me->edata; + ss->ldata = &me->ldata; + ss->pdata = &me->pdata; } /* Sculpt Face Sets. */ @@ -2233,7 +2238,7 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob) pbvh = build_pbvh_for_dynamic_topology(ob); ob->sculpt->pbvh = pbvh; - //reorder mesh elements to improve memory cache performance + // reorder mesh elements to improve memory cache performance SCULPT_reorder_bmesh(ob->sculpt); } else { diff --git a/source/blender/bmesh/intern/bmesh_log.c b/source/blender/bmesh/intern/bmesh_log.c index c6c96481e7f..cd5cd05f10a 100644 --- a/source/blender/bmesh/intern/bmesh_log.c +++ b/source/blender/bmesh/intern/bmesh_log.c @@ -782,7 +782,8 @@ void BM_log_set_cd_offsets(BMLog *log, int cd_dyn_vert) log->cd_dyn_vert = cd_dyn_vert; } -void BM_log_set_bm(BMesh *bm, BMLog *log) { +void BM_log_set_bm(BMesh *bm, BMLog *log) +{ log->bm = bm; } diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c index 9beeb5c900b..780b4a06044 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.c +++ b/source/blender/bmesh/intern/bmesh_polygon.c @@ -29,6 +29,7 @@ #include "MEM_guardedalloc.h" #include "BLI_alloca.h" +#include "BLI_compiler_attrs.h" #include "BLI_heap.h" #include "BLI_linklist.h" #include "BLI_math.h" @@ -1105,20 +1106,20 @@ bool BM_face_point_inside_test(const BMFace *f, const float co[3]) * \note use_tag tags new flags and edges. */ void BM_face_triangulate(BMesh *bm, - BMFace *f, - BMFace **r_faces_new, - int *r_faces_new_tot, - BMEdge **r_edges_new, - int *r_edges_new_tot, - LinkNode **r_faces_double, - const int quad_method, - const int ngon_method, - const bool use_tag, - /* use for ngons only! */ - MemArena *pf_arena, + BMFace *f, + BMFace **r_faces_new, + int *r_faces_new_tot, + BMEdge **r_edges_new, + int *r_edges_new_tot, + LinkNode **r_faces_double, + const int quad_method, + const int ngon_method, + const bool use_tag, + /* use for ngons only! */ + MemArena *pf_arena, - /* use for MOD_TRIANGULATE_NGON_BEAUTY only! */ - struct Heap *pf_heap) + /* use for MOD_TRIANGULATE_NGON_BEAUTY only! */ + struct Heap *pf_heap) { const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS); const bool use_beauty = (ngon_method == MOD_TRIANGULATE_NGON_BEAUTY); @@ -1467,7 +1468,6 @@ void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4]) r_verts[3] = l->v; } - /** * faster alternative to: * BM_iter_as_array(bm, BM_LOOPS_OF_FACE, f, (void **)l, 4); diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 4f2bde51971..0694a9d5b42 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -46,6 +46,7 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "BKE_attribute.h" #include "BKE_brush.h" #include "BKE_ccg.h" #include "BKE_colortools.h" @@ -120,7 +121,6 @@ void SCULPT_vertex_random_access_ensure(SculptSession *ss) } } - /* Sculpt PBVH abstraction API * * This is read-only, for writing use PBVH vertex iterators. There vd.index matches @@ -168,7 +168,7 @@ const float *SCULPT_vertex_origco_get(SculptSession *ss, SculptVertRef vertex) const float *SCULPT_vertex_co_get(SculptSession *ss, SculptVertRef index) { if (ss->bm) { - return ((BMVert*)index.i)->co; + return ((BMVert *)index.i)->co; } switch (BKE_pbvh_type(ss->pbvh)) { @@ -335,6 +335,132 @@ void SCULPT_vertex_persistent_normal_get(SculptSession *ss, SCULPT_vertex_normal_get(ss, index, no); } +static bool sculpt_temp_customlayer_get(SculptSession *ss, + AttributeDomain domain, + int proptype, + char *name, + SculptCustomLayer *out, + bool autocreate) +{ + switch (BKE_pbvh_type(ss->pbvh)) { + case PBVH_BMESH: { + CustomData *cdata = NULL; + + if (!ss->bm) { + return false; + } + + switch (domain) { + case ATTR_DOMAIN_POINT: + cdata = &ss->bm->vdata; + break; + case ATTR_DOMAIN_FACE: + cdata = &ss->bm->pdata; + break; + default: + return false; + } + + int idx = CustomData_get_named_layer_index(cdata, proptype, name); + + if (idx < 0) { + if (!autocreate) { + return false; + } + + BM_data_layer_add_named(ss->bm, cdata, proptype, name); + idx = CustomData_get_named_layer_index(cdata, proptype, name); + cdata->layers[idx].flag |= CD_FLAG_TEMPORARY; + SCULPT_dyntopo_node_layers_update_offsets(ss); + } + + out->data = NULL; + out->is_cdlayer = true; + out->layer = cdata->layers + idx; + out->cd_offset = out->layer->offset; + out->elemsize = CustomData_get_elem_size(out->layer); + + break; + } + case PBVH_FACES: { + CustomData *cdata = NULL; + int totelem = 0; + + switch (domain) { + case ATTR_DOMAIN_POINT: + totelem = ss->totvert; + cdata = ss->vdata; + break; + case ATTR_DOMAIN_FACE: + totelem = ss->totfaces; + cdata = ss->pdata; + break; + default: + return false; + } + + int idx = CustomData_get_named_layer_index(cdata, proptype, name); + + if (idx < 0) { + if (!autocreate) { + return false; + } + + CustomData_add_layer_named(cdata, proptype, CD_CALLOC, NULL, totelem, name); + idx = CustomData_get_named_layer_index(cdata, proptype, name); + + cdata->layers[idx].flag |= CD_FLAG_TEMPORARY; + } + + out->data = NULL; + out->is_cdlayer = true; + out->layer = cdata->layers + idx; + out->cd_offset = -1; + out->data = out->layer->data; + out->elemsize = CustomData_get_elem_size(out->layer); + break; + } + case PBVH_GRIDS: { + CustomData *cdata = NULL; + int totelem = 0; + + switch (domain) { + case ATTR_DOMAIN_POINT: + totelem = BKE_pbvh_get_grid_num_vertices(ss->pbvh); + cdata = &ss->temp_vdata; + break; + case ATTR_DOMAIN_FACE: + // not supported + return false; + default: + return false; + } + + int idx = CustomData_get_named_layer_index(cdata, proptype, name); + + if (idx < 0) { + if (!autocreate) { + return false; + } + + CustomData_add_layer_named(cdata, proptype, CD_CALLOC, NULL, totelem, name); + idx = CustomData_get_named_layer_index(cdata, proptype, name); + } + + out->data = NULL; + out->is_cdlayer = true; + out->layer = cdata->layers + idx; + out->cd_offset = -1; + out->data = out->layer->data; + out->elemsize = CustomData_get_elem_size(out->layer); + + break; + } + } + + return true; +} + float SCULPT_vertex_mask_get(SculptSession *ss, SculptVertRef index) { BMVert *v; @@ -358,6 +484,21 @@ float SCULPT_vertex_mask_get(SculptSession *ss, SculptVertRef index) return 0.0f; } +bool SCULPT_temp_customlayer_ensure(SculptSession *ss, + AttributeDomain domain, + int proptype, + char *name) +{ + SculptCustomLayer scl; + return sculpt_temp_customlayer_get(ss, domain, proptype, name, &scl, true); +} + +bool SCULPT_temp_customlayer_get( + SculptSession *ss, AttributeDomain domain, int proptype, char *name, SculptCustomLayer *scl) +{ + return sculpt_temp_customlayer_get(ss, domain, proptype, name, scl, true); +} + SculptVertRef SCULPT_active_vertex_get(SculptSession *ss) { if (ELEM(BKE_pbvh_type(ss->pbvh), PBVH_FACES, PBVH_BMESH, PBVH_GRIDS)) { @@ -1095,10 +1236,9 @@ static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter, iter->size++; } - static void sculpt_vertex_neighbor_add_nocheck(SculptVertexNeighborIter *iter, - SculptVertRef neighbor, - int neighbor_index) + SculptVertRef neighbor, + int neighbor_index) { if (iter->size >= iter->capacity) { iter->capacity += SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY; @@ -1147,7 +1287,8 @@ static void sculpt_vertex_neighbors_get_bmesh(SculptSession *ss, iter, BKE_pbvh_make_vref((intptr_t)e->v2), BM_elem_index_get(e->v2)); e = e->v1_disk_link.next; - } else { + } + else { sculpt_vertex_neighbor_add_nocheck( iter, BKE_pbvh_make_vref((intptr_t)e->v1), BM_elem_index_get(e->v1)); @@ -1527,7 +1668,9 @@ void SCULPT_floodfill_add_initial(SculptFloodFill *flood, SculptVertRef vertex) BLI_gsqueue_push(flood->queue, &vertex); } -void SCULPT_floodfill_add_and_skip_initial(SculptSession *ss, SculptFloodFill *flood, SculptVertRef vertex) +void SCULPT_floodfill_add_and_skip_initial(SculptSession *ss, + SculptFloodFill *flood, + SculptVertRef vertex) { BLI_gsqueue_push(flood->queue, &vertex); BLI_BITMAP_ENABLE(flood->visited_vertices, BKE_pbvh_vertex_index_to_table(ss->pbvh, vertex)); @@ -1675,7 +1818,7 @@ static bool sculpt_tool_is_proxy_used(const char sculpt_tool) static bool sculpt_brush_use_topology_rake(const SculptSession *ss, const Brush *brush) { return SCULPT_TOOL_HAS_TOPOLOGY_RAKE(brush->sculpt_tool) && - (brush->topology_rake_factor > 0.0f) && (ss->bm != NULL); + (brush->topology_rake_factor > 0.0f) && (ss->bm != NULL); } /** @@ -3492,14 +3635,12 @@ static void bmesh_topology_rake( for (iteration = 0; iteration <= count; iteration++) { - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .strength = factor, - .rake_projection = brush->topology_rake_projection - }; + SculptThreadedTaskData data = {.sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .strength = factor, + .rake_projection = brush->topology_rake_projection}; TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); @@ -6882,10 +7023,11 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe float spacing = (float)brush->topology_rake_spacing / 100.0f; use_topology_rake = use_topology_rake && - paint_stroke_apply_subspacing(ss->cache->stroke, - spacing, - PAINT_MODE_SCULPT, - &ss->cache->last_rake_t[SCULPT_get_symmetry_pass(ss)]); + paint_stroke_apply_subspacing( + ss->cache->stroke, + spacing, + PAINT_MODE_SCULPT, + &ss->cache->last_rake_t[SCULPT_get_symmetry_pass(ss)]); } if (use_topology_rake) { diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c index 3e7d0fde942..4bc8e7ff955 100644 --- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c +++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c @@ -138,6 +138,9 @@ void SCULPT_dynamic_topology_triangulate(SculptSession *ss, BMesh *bm) MemArena *pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__); LinkNode *f_double = NULL; + BMFace **faces_array = NULL; + BLI_array_declare(faces_array); + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { if (f->len <= 3) { continue; @@ -146,9 +149,9 @@ void SCULPT_dynamic_topology_triangulate(SculptSession *ss, BMesh *bm) bool sel = BM_elem_flag_test(f, BM_ELEM_SELECT); int faces_array_tot = f->len; - BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot); - - printf("%d: ", f->head.hflag); + BLI_array_clear(faces_array); + BLI_array_grow_items(faces_array, faces_array_tot); + // BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot); BM_face_triangulate(bm, f, @@ -163,8 +166,6 @@ void SCULPT_dynamic_topology_triangulate(SculptSession *ss, BMesh *bm) pf_arena, NULL); - printf("%d, ", f->head.hflag); - for (int i = 0; i < faces_array_tot; i++) { BMFace *f2 = faces_array[i]; @@ -181,8 +182,6 @@ void SCULPT_dynamic_topology_triangulate(SculptSession *ss, BMesh *bm) } } - printf("\n"); - while (f_double) { LinkNode *next = f_double->next; BM_face_kill(bm, f_double->link); @@ -191,6 +190,7 @@ void SCULPT_dynamic_topology_triangulate(SculptSession *ss, BMesh *bm) } BLI_memarena_free(pf_arena); + MEM_SAFE_FREE(faces_array); ss->totfaces = ss->totpoly = ss->bm->totface; ss->totvert = ss->bm->totvert; diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index ea7a026409d..21d0b5b341a 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -30,12 +30,16 @@ #include "DNA_vec_types.h" #include "BLI_bitmap.h" +#include "BLI_compiler_compat.h" #include "BLI_gsqueue.h" #include "BLI_threads.h" +#include "BKE_attribute.h" #include "BKE_paint.h" #include "BKE_pbvh.h" +#include "bmesh.h" + struct AutomaskingCache; struct KeyBlock; struct Object; @@ -747,6 +751,14 @@ struct SculptRakeData { float follow_co[3]; }; +typedef struct SculptCustomLayer { + bool is_cdlayer; // false for multires data + void *data; // only valid for multires and face + int elemsize; + int cd_offset; // for bmesh + CustomDataLayer *layer; // not for multires +} SculptCustomLayer; + /* Single struct used by all BLI_task threaded callbacks, let's avoid adding 10's of those... */ typedef struct SculptThreadedTaskData { struct bContext *C; @@ -866,6 +878,7 @@ typedef struct SculptThreadedTaskData { float smooth_projection; float rake_projection; + SculptCustomLayer *scl; } SculptThreadedTaskData; /*************** Brush testing declarations ****************/ @@ -1519,3 +1532,31 @@ int SCULPT_get_symmetry_pass(const SculptSession *ss); void SCULPT_on_sculptsession_bmesh_free(SculptSession *ss); void SCULPT_reorder_bmesh(SculptSession *ss); + +static inline void *SCULPT_temp_cdata_get(SculptVertRef vertex, SculptCustomLayer *scl) +{ + if (scl->data) { + char *p = (char *)scl->data; + return p + scl->elemsize * (int)vertex.i; + } + else { + BMVert *v = (BMVert *)vertex.i; + return BM_ELEM_CD_GET_VOID_P(v, scl->cd_offset); + } +} + +/* +create a custom vertex or face attribute. +always create all of your attributes together with SCULPT_temp_customlayer_ensure, + +then initialize their SculptCustomLayer's with SCULPT_temp_customlayer_get +afterwards. Otherwise customdata offsets will be wrong (for PBVH_BMESH). + +return true on success. if false layer was not created. +*/ +bool SCULPT_temp_customlayer_ensure(SculptSession *ss, + AttributeDomain domain, + int proptype, + char *name); +bool SCULPT_temp_customlayer_get( + SculptSession *ss, AttributeDomain domain, int proptype, char *name, SculptCustomLayer *scl); diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c index e92d4b17022..82818632782 100644 --- a/source/blender/editors/sculpt_paint/sculpt_smooth.c +++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c @@ -33,6 +33,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "BKE_attribute.h" #include "BKE_brush.h" #include "BKE_context.h" #include "BKE_mesh.h" @@ -141,9 +142,95 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss, } } +void SCULPT_neighbor_coords_average_interior_velocity(SculptSession *ss, + float result[3], + SculptVertRef vertex, + float projection, + SculptCustomLayer *scl) +{ + float avg[3] = {0.0f, 0.0f, 0.0f}; + int total = 0; + int neighbor_count = 0; + const bool is_boundary = SCULPT_vertex_is_boundary(ss, vertex); + const float *co = SCULPT_vertex_co_get(ss, vertex); + float no[3]; + + if (projection > 0.0f) { + SCULPT_vertex_normal_get(ss, vertex, no); + } + + float vel[3]; + + copy_v3_v3(vel, (float *)SCULPT_temp_cdata_get(vertex, scl)); + mul_v3_fl(vel, 0.4f); + + SculptVertexNeighborIter ni; + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) { + neighbor_count++; + + float tmp[3]; + bool ok = false; + + float *vel2 = SCULPT_temp_cdata_get(ni.vertex, scl); + + // propegate smooth velocities a bit + madd_v3_v3fl(vel2, vel, 1.0f / (float)ni.size); + + if (is_boundary) { + /* Boundary vertices use only other boundary vertices. */ + if (SCULPT_vertex_is_boundary(ss, ni.vertex)) { + copy_v3_v3(tmp, SCULPT_vertex_co_get(ss, ni.vertex)); + ok = true; + } + } + else { + /* Interior vertices use all neighbors. */ + copy_v3_v3(tmp, SCULPT_vertex_co_get(ss, ni.vertex)); + ok = true; + } + + if (!ok) { + continue; + } + + if (projection > 0.0f) { + sub_v3_v3(tmp, co); + float fac = dot_v3v3(tmp, no); + madd_v3_v3fl(tmp, no, -fac * projection); + add_v3_v3(avg, tmp); + } + else { + add_v3_v3(avg, tmp); + } + + total++; + } + SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); + + /* Do not modify corner vertices. */ + if (neighbor_count <= 2) { + copy_v3_v3(result, SCULPT_vertex_co_get(ss, vertex)); + return; + } + + /* Avoid division by 0 when there are no neighbors. */ + if (total == 0) { + copy_v3_v3(result, SCULPT_vertex_co_get(ss, vertex)); + return; + } + + mul_v3_v3fl(result, avg, 1.0f / total); + + if (projection > 0.0f) { + add_v3_v3(result, co); + } +} /* For bmesh: Average surrounding verts based on an orthogonality measure. * Naturally converges to a quad-like structure. */ -void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], BMVert *v, float projection) +void SCULPT_bmesh_four_neighbor_average(float avg[3], + float direction[3], + BMVert *v, + float projection) { float avg_co[3] = {0.0f, 0.0f, 0.0f}; @@ -161,7 +248,7 @@ void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], BMVert float vec[3]; sub_v3_v3v3(vec, v_other->co, v->co); - madd_v3_v3fl(vec, v->no, -dot_v3v3(vec, v->no)*projection); + madd_v3_v3fl(vec, v->no, -dot_v3v3(vec, v->no) * projection); normalize_v3(vec); /* fac is a measure of how orthogonal or parallel the edge is @@ -180,7 +267,7 @@ void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], BMVert /* Preserve volume. */ float vec[3]; sub_v3_v3(avg, v->co); - mul_v3_v3fl(vec, v->no, dot_v3v3(avg, v->no)*projection); + mul_v3_v3fl(vec, v->no, dot_v3v3(avg, v->no) * projection); sub_v3_v3(avg, vec); add_v3_v3(avg, v->co); } @@ -193,9 +280,9 @@ void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], BMVert * account. */ void SCULPT_neighbor_coords_average(SculptSession *ss, - float result[3], - SculptVertRef vertex, - float projection) + float result[3], + SculptVertRef vertex, + float projection) { float avg[3] = {0.0f, 0.0f, 0.0f}; float *co, no[3]; @@ -497,6 +584,63 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata, } #endif +static void do_smooth_brush_task_cb_ex_scl(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + Sculpt *sd = data->sd; + const Brush *brush = data->brush; + float bstrength = data->strength; + float projection = data->smooth_projection; + + SculptCustomLayer *scl = data->scl; + + PBVHVertexIter vd; + + CLAMP(bstrength, 0.0f, 1.0f); + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + (vd.mask ? *vd.mask : 0.0f), + vd.vertex, + thread_id); + + float avg[3], val[3]; + + SCULPT_neighbor_coords_average_interior_velocity(ss, avg, vd.vertex, projection, scl); + + sub_v3_v3v3(val, avg, vd.co); + + float *vel = (float *)SCULPT_temp_cdata_get(vd.vertex, scl); + interp_v3_v3v3(vel, vel, val, 0.5); + + madd_v3_v3v3fl(val, vd.co, vel, fade); + + SCULPT_clip(sd, ss, vd.co, val); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + void SCULPT_smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, @@ -519,6 +663,18 @@ void SCULPT_smooth(Sculpt *sd, count = (int)(bstrength * max_iterations); last = max_iterations * (bstrength - count * fract); + SculptCustomLayer scl; +#if 0 + bool have_scl = smooth_mask ? false : + SCULPT_temp_customlayer_ensure( + ss, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, "__scl_smooth_vel"); + if (have_scl) { + SCULPT_temp_customlayer_get(ss, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, "__scl_smooth_vel", &scl); + } +#else + bool have_scl = false; +#endif + if (type == PBVH_FACES && !ss->pmap) { BLI_assert(!"sculpt smooth: pmap missing"); return; @@ -536,19 +692,23 @@ void SCULPT_smooth(Sculpt *sd, for (iteration = 0; iteration <= count; iteration++) { const float strength = (iteration != count) ? 1.0f : last; - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .smooth_mask = smooth_mask, - .strength = strength, - .smooth_projection = projection, - }; + SculptThreadedTaskData data = {.sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .smooth_mask = smooth_mask, + .strength = strength, + .smooth_projection = projection, + .scl = have_scl ? &scl : NULL}; TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_task_cb_ex, &settings); + if (have_scl) { + BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_task_cb_ex_scl, &settings); + } + else { + BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_task_cb_ex, &settings); + } #ifdef PROXY_ADVANCED BKE_pbvh_gather_proxyarray(ss->pbvh, nodes, totnode);