Sculpt-dev: Improve autosmooth performance

* PBVH_FACES now uses MDynTopoVert (have got
  to rename it) to store boundary/corner/visibility
  flags the same way PBVH_BMESH does.
* Fixed brush add/sub buttons in header not
  working
* Fixed inverted brushes feeding negative strength
  to sub commands (like autosmooth, which flips it
  to sharpen mode).
This commit is contained in:
Joseph Eagar 2021-09-28 23:14:27 -07:00
parent 486627215c
commit 06e8cc0256
16 changed files with 453 additions and 174 deletions

View File

@ -794,7 +794,6 @@ void range_tree_uint_take(RangeTreeUInt *rt, const uint value)
range_tree_uint_take_impl(rt, value, node);
}
#pragma optimize("", off)
bool range_tree_uint_retake(RangeTreeUInt *rt, const uint value)
{
Node *node = rt_find_node_from_value(rt, value);

View File

@ -300,6 +300,15 @@ class UnifiedPaintPanel:
itemicon = "CHECKBOX_DEHLT"
row3.prop_enum(finalch, typeprop, item.identifier, icon=itemicon)
elif header and ch.idname == "direction":
row2 = row.row(align=True)
row2.use_property_split = False
row2.use_property_decorate = False
#replicate pre-existing functionality of direction showing up as +/- in the header
row2.prop_enum(finalch, typeprop, "ADD", text="")
row2.prop_enum(finalch, typeprop, "SUBTRACT", text="")
pass
elif expand is not None:
row.prop(finalch, typeprop, icon=icon, text=text, slider=slider, expand=expand)
else:

View File

@ -274,7 +274,19 @@ class _draw_tool_settings_context_mode:
# direction
if not capabilities.has_direction:
layout.row().prop(brush, "direction", expand=True, text="")
row = layout.row()
UnifiedPaintPanel.prop_unified(
layout,
context,
brush,
"direction",
pressure_name=pressure_name,
unified_name="use_unified_strength",
text="",
header=True,
expand=True
)
if capabilities.has_color:
UnifiedPaintPanel.prop_unified_color(layout, context, brush, "color", text="")

View File

@ -538,7 +538,7 @@ typedef struct SculptArray {
int *symmetry_pass;
float *smooth_strength;
struct SculptCustomLayer *scl_inst, *scl_sym;
} SculptArray;
typedef struct SculptFakeNeighbors {

View File

@ -110,6 +110,7 @@ struct BMVert;
struct BMEdge;
struct BMFace;
struct CCGElem;
struct MeshElemMap;
struct CCGKey;
struct CustomData;
struct TableGSet;
@ -913,6 +914,15 @@ typedef struct SculptLayerEntry {
int BKE_pbvh_do_fset_symmetry(int fset, const int symflag, const float *co);
bool BKE_pbvh_check_vert_boundary(PBVH *pbvh, struct BMVert *v);
void BKE_pbvh_update_vert_boundary_faces(int *face_sets,
struct MVert *mvert,
struct MEdge *medge,
struct MLoop *mloop,
struct MPoly *mpoly,
struct MDynTopoVert *mdyntopo_verts,
struct MeshElemMap *pmap,
SculptVertRef vertex);
#ifdef __cplusplus
}
#endif

View File

@ -441,6 +441,7 @@ MAKE_ENUM(elastic_deform_type, "Deformation", "Deformation type that is used in
{BRUSH_ELASTIC_DEFORM_TWIST, "TWIST", "NONE", "Twist", ""},
{-1}
})
MAKE_BOOL(use_ctrl_invert, "Use Ctrl Invert", "Take brush addition or subtraction mode into account", true)
//MAKE_FLOAT3_EX
/* clang-format on */

View File

@ -1397,6 +1397,9 @@ BrushCommand *BKE_brush_command_init(BrushCommand *command, int tool)
#define float_set_uninherit(chset, channel, val) \
_float_set_uninherit(chset, MAKE_BUILTIN_CH_NAME(channel), val)
#define int_set_uninherit(chset, channel, val) \
_int_set_uninherit(chset, MAKE_BUILTIN_CH_NAME(channel), val)
static void _float_set_uninherit(BrushChannelSet *chset, const char *channel, float val)
{
BrushChannel *ch = BKE_brush_channelset_lookup(chset, channel);
@ -1410,6 +1413,19 @@ static void _float_set_uninherit(BrushChannelSet *chset, const char *channel, fl
ch->flag &= ~BRUSH_CHANNEL_INHERIT;
}
static void _int_set_uninherit(BrushChannelSet *chset, const char *channel, int val)
{
BrushChannel *ch = BKE_brush_channelset_lookup(chset, channel);
if (!ch) {
printf("%s: unknown channel %s\n", __func__, channel);
return;
}
ch->ivalue = val;
ch->flag &= ~BRUSH_CHANNEL_INHERIT;
}
/*flag all mappings to use inherited curves even if owning channel
is not set to inherit.*/
void BKE_brush_commandset_inherit_all_mappings(BrushChannelSet *chset)
@ -1463,6 +1479,7 @@ static void bke_builtin_commandlist_create_paint(Brush *brush,
ch->flag |= BRUSH_CHANNEL_INHERIT;
}
int_set_uninherit(cmd->params, use_ctrl_invert, false);
float_set_uninherit(cmd->params, strength, autosmooth);
float_set_uninherit(cmd->params, radius, radius * autosmooth_scale);
float_set_uninherit(cmd->params, projection, autosmooth_projection);
@ -1580,6 +1597,7 @@ void BKE_builtin_commandlist_create(Brush *brush,
ch->flag |= BRUSH_CHANNEL_INHERIT;
}
int_set_uninherit(cmd->params, use_ctrl_invert, false);
float_set_uninherit(cmd->params, strength, autosmooth);
float_set_uninherit(cmd->params, radius, radius * autosmooth_scale);
float_set_uninherit(cmd->params, projection, autosmooth_projection);
@ -1620,6 +1638,7 @@ void BKE_builtin_commandlist_create(Brush *brush,
ch->flag |= BRUSH_CHANNEL_INHERIT;
}
int_set_uninherit(cmd->params, use_ctrl_invert, false);
float_set_uninherit(cmd->params, strength, topology_rake);
float_set_uninherit(cmd->params, radius, radius * topology_rake_scale);
float_set_uninherit(cmd->params, projection, topology_rake_projection);
@ -1637,6 +1656,7 @@ void BKE_builtin_commandlist_create(Brush *brush,
radius2 *= radius;
int_set_uninherit(cmd->params, use_ctrl_invert, false);
float_set_uninherit(cmd->params, spacing, spacing);
float_set_uninherit(cmd->params, radius, radius2);
}

View File

@ -807,6 +807,7 @@ void BKE_brush_builtin_patch(Brush *brush, int tool)
ADDCH(radius_unit);
ADDCH(unprojected_radius);
ADDCH(use_ctrl_invert);
ADDCH(tilt_strength_factor);
ADDCH(autosmooth);

View File

@ -2203,6 +2203,7 @@ static PBVH *build_pbvh_for_dynamic_topology(Object *ob)
static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool respect_hide)
{
SculptSession *ss = ob->sculpt;
Mesh *me = BKE_object_get_original_mesh(ob);
const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop);
PBVH *pbvh = BKE_pbvh_new();
@ -2214,6 +2215,19 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool
BKE_sculpt_sync_face_set_visibility(me, NULL);
if (!ss->pmap) {
BKE_mesh_vert_poly_map_create(&ss->pmap,
&ss->pmap_mem,
me->mvert,
me->medge,
me->mpoly,
me->mloop,
me->totvert,
me->totpoly,
me->totloop,
false);
}
BKE_sculptsession_check_mdyntopo(ob->sculpt, me->totvert);
BKE_pbvh_build_mesh(pbvh,
@ -2294,6 +2308,16 @@ static void init_mdyntopo_layer(SculptSession *ss, int totvert)
for (int i = 0; i < totvert; i++, mv++) {
mv->flag = DYNVERT_NEED_BOUNDARY | DYNVERT_NEED_VALENCE | DYNVERT_NEED_DISK_SORT;
mv->stroke_id = -1;
SculptVertRef vertex = {.i = i};
BKE_pbvh_update_vert_boundary_faces(ss->face_sets,
ss->mvert,
ss->medge,
ss->mloop,
ss->mpoly,
ss->mdyntopo_verts,
ss->pmap,
vertex);
}
}
PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)

View File

@ -35,6 +35,7 @@
#include "BKE_ccg.h"
#include "BKE_mesh.h" /* for BKE_mesh_calc_normals */
#include "BKE_mesh_mapping.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
#include "BKE_subdiv_ccg.h"
@ -4125,3 +4126,88 @@ void BKE_pbvh_set_symmetry(PBVH *pbvh, int symmetry, int boundary_symmetry)
}
}
}
void BKE_pbvh_update_vert_boundary_faces(int *face_sets,
MVert *mvert,
MEdge *medge,
MLoop *mloop,
MPoly *mpoly,
MDynTopoVert *mdyntopo_verts,
MeshElemMap *pmap,
SculptVertRef vertex)
{
MDynTopoVert *mv = mdyntopo_verts + vertex.i;
MeshElemMap *vert_map = &pmap[vertex.i];
int last_fset = 0;
int last_fset2 = 0;
mv->flag &= ~(DYNVERT_BOUNDARY | DYNVERT_FSET_BOUNDARY | DYNVERT_NEED_BOUNDARY |
DYNVERT_FSET_CORNER | DYNVERT_CORNER | DYNVERT_SEAM_BOUNDARY |
DYNVERT_SHARP_BOUNDARY | DYNVERT_SEAM_CORNER | DYNVERT_SHARP_CORNER);
int totsharp = 0, totseam = 0;
int visible = false;
for (int i = 0; i < vert_map->count; i++) {
int f_i = vert_map->indices[i];
MPoly *mp = mpoly + f_i;
MLoop *ml = mloop + mp->loopstart;
int j = 0;
for (j = 0; j < mp->totloop; j++, ml++) {
if (ml->v == (int)vertex.i) {
break;
}
}
if (j < mp->totloop) {
MEdge *me = medge + ml->e;
if (me->flag & ME_SHARP) {
mv->flag |= DYNVERT_SHARP_BOUNDARY;
totsharp++;
}
if (me->flag & ME_SEAM) {
mv->flag |= DYNVERT_SEAM_BOUNDARY;
totseam++;
}
}
int fset = face_sets[f_i];
if (fset > 0) {
visible = true;
}
else {
fset = -fset;
}
if (i > 0 && fset != last_fset) {
mv->flag |= DYNVERT_FSET_BOUNDARY;
if (i > 1 && last_fset2 != last_fset) {
mv->flag |= DYNVERT_FSET_CORNER;
}
}
if (i > 0 && last_fset != fset) {
last_fset2 = last_fset;
}
last_fset = fset;
}
if (!visible) {
mv->flag |= DYNVERT_VERT_FSET_HIDDEN;
}
if (totsharp > 2) {
mv->flag |= DYNVERT_SHARP_CORNER;
}
if (totseam > 2) {
mv->flag |= DYNVERT_SEAM_CORNER;
}
}

View File

@ -159,6 +159,7 @@ struct PBVH {
MVert *verts;
const MPoly *mpoly;
const MLoop *mloop;
struct MDynTopoVert *mdyntopo_verts;
const MLoopTri *looptri;
CustomData *vdata;
CustomData *ldata;
@ -218,7 +219,6 @@ struct PBVH {
int balance_counter;
int stroke_id; // used to keep origdata up to date in PBVH_BMESH
struct MDynTopoVert *mdyntopo_verts;
};
/* pbvh.c */

View File

@ -921,13 +921,15 @@ void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const BMAllocTem
CustomData_bmesh_init_pool(&bm_dst->pdata, allocsize->totface, BM_FACE);
// flag mesh id layer as temporary
for (int i = 0; i < 4; i++) {
CustomData *cdata = dstdatas[i];
if (!(bm_dst->idmap.flag & BM_PERMANENT_IDS)) {
for (int i = 0; i < 4; i++) {
CustomData *cdata = dstdatas[i];
if (CustomData_has_layer(cdata, CD_MESH_ID)) {
int idx = CustomData_get_layer_index(cdata, CD_MESH_ID);
if (CustomData_has_layer(cdata, CD_MESH_ID)) {
int idx = CustomData_get_layer_index(cdata, CD_MESH_ID);
cdata->layers[idx].flag |= CD_FLAG_TEMPORARY | CD_FLAG_ELEM_NOCOPY;
cdata->layers[idx].flag |= CD_FLAG_TEMPORARY | CD_FLAG_ELEM_NOCOPY;
}
}
}
}
@ -976,7 +978,7 @@ void BM_mesh_copy_init_customdata_all_layers(BMesh *bm_dst,
bm_update_idmap_cdlayers(bm_dst);
}
BMesh *BM_mesh_copy(BMesh *bm_old)
BMesh *BM_mesh_copy_ex(BMesh *bm_old, struct BMeshCreateParams *params)
{
BMesh *bm_new;
BMVert *v, *v_new, **vtable = NULL;
@ -987,19 +989,29 @@ BMesh *BM_mesh_copy(BMesh *bm_old)
BMIter iter;
int i;
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_BM(bm_old);
struct BMeshCreateParams _params;
if (!params) {
_params = ((struct BMeshCreateParams){
.use_toolflags = bm_old->use_toolflags,
.id_elem_mask = bm_old->idmap.flag & (BM_VERT | BM_EDGE | BM_LOOP | BM_FACE),
.create_unique_ids = !!(bm_old->idmap.flag & BM_HAS_IDS),
.id_map = !!(bm_old->idmap.flag & BM_HAS_ID_MAP),
.temporary_ids = !(bm_old->idmap.flag & BM_PERMANENT_IDS),
.no_reuse_ids = !!(bm_old->idmap.flag & BM_NO_REUSE_IDS)});
params = &_params;
}
/* allocate a bmesh */
bm_new = BM_mesh_create(
&allocsize,
&((struct BMeshCreateParams){.use_toolflags = bm_old->use_toolflags,
.id_elem_mask = bm_old->idmap.flag &
(BM_VERT | BM_EDGE | BM_LOOP | BM_FACE),
.create_unique_ids = !!(bm_old->idmap.flag & BM_HAS_IDS),
.id_map = !!(bm_old->idmap.flag & BM_HAS_ID_MAP),
.temporary_ids = !(bm_old->idmap.flag & BM_PERMANENT_IDS),
.no_reuse_ids = !!(bm_old->idmap.flag & BM_NO_REUSE_IDS)}));
bm_new = BM_mesh_create(&allocsize, params);
BM_mesh_copy_init_customdata(bm_new, bm_old, &allocsize);
if (params->copy_all_layers) {
BM_mesh_copy_init_customdata_all_layers(
bm_new, bm_old, BM_VERT | BM_EDGE | BM_LOOP | BM_FACE, &allocsize);
}
else {
BM_mesh_copy_init_customdata(bm_new, bm_old, &allocsize);
}
if (bm_old->idmap.flag & BM_HAS_IDS) {
MEM_SAFE_FREE(bm_new->idmap.map);
@ -1139,6 +1151,11 @@ BMesh *BM_mesh_copy(BMesh *bm_old)
return bm_new;
}
BMesh *BM_mesh_copy(BMesh *bm_old)
{
return BM_mesh_copy_ex(bm_old, NULL);
}
/* ME -> BM */
char BM_vert_flag_from_mflag(const char mflag)
{

View File

@ -43,6 +43,7 @@ struct BMeshCreateParams {
uint no_reuse_ids : 1; // do not reuse IDs; a GHash will be used internally instead of a lookup
// array
uint temporary_ids : 1;
uint copy_all_layers : 1; // used by BM_mesh_copy_ex
};
// used to temporary save/restore element IDs

View File

@ -1796,6 +1796,7 @@ static void sculpt_vertex_neighbors_get_bmesh(const SculptSession *ss,
iter->is_duplicate = false;
iter->size = 0;
iter->num_duplicates = 0;
iter->has_edge = true;
iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
iter->neighbors = iter->neighbors_fixed;
iter->neighbor_indices = iter->neighbor_indices_fixed;
@ -1851,6 +1852,7 @@ static void sculpt_vertex_neighbors_get_faces(const SculptSession *ss,
iter->neighbors = iter->neighbors_fixed;
iter->neighbor_indices = iter->neighbor_indices_fixed;
iter->is_duplicate = false;
iter->has_edge = true;
for (int i = 0; i < ss->pmap[index].count; i++) {
if (ss->face_sets[vert_map->indices[i]] < 0) {
@ -1859,23 +1861,31 @@ static void sculpt_vertex_neighbors_get_faces(const SculptSession *ss,
}
const MPoly *p = &ss->mpoly[vert_map->indices[i]];
uint f_adj_v[2];
if (poly_get_adj_loops_from_vert(p, ss->mloop, index, f_adj_v) != -1) {
for (int j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
MLoop *l = &ss->mloop[p->loopstart];
int e1, e2;
bool ok = false;
for (int j = 0; j < p->totloop; j++, l++) {
if (l->v == index) {
f_adj_v[0] = ME_POLY_LOOP_PREV(ss->mloop, p, j)->v;
f_adj_v[1] = ME_POLY_LOOP_NEXT(ss->mloop, p, j)->v;
e1 = ME_POLY_LOOP_PREV(ss->mloop, p, j)->e;
e2 = l->e;
ok = true;
break;
}
}
if (ok) {
for (int j = 0; j < 2; j += 1) {
int e = 0;
if (f_adj_v[j] != index) {
int loopidx = p->loopstart;
for (int k = 0; k < p->totloop; k++, loopidx++) {
const MEdge *e2 = &ss->medge[ss->mloop[loopidx].e];
if ((e2->v1 == index && e2->v2 == f_adj_v[j]) ||
(e2->v2 == index && e2->v1 == f_adj_v[j])) {
e = e2 - ss->medge;
}
}
sculpt_vertex_neighbor_add(
iter, BKE_pbvh_make_vref(f_adj_v[j]), BKE_pbvh_make_eref(e), f_adj_v[j]);
iter, BKE_pbvh_make_vref(f_adj_v[j]), BKE_pbvh_make_eref(j ? e2 : e1), f_adj_v[j]);
}
}
}
@ -1910,8 +1920,9 @@ static void sculpt_vertex_neighbors_get_faces_vemap(const SculptSession *ss,
const MEdge *me = &ss->medge[vert_map->indices[i]];
unsigned int v = me->v1 == (unsigned int)vertex.i ? me->v2 : me->v1;
MDynTopoVert *mv = ss->mdyntopo_verts + v;
if (ss->face_sets[v] < 0) {
if (mv->flag & DYNVERT_VERT_FSET_HIDDEN) {
/* Skip connectivity from hidden faces. */
continue;
}
@ -2128,18 +2139,39 @@ static bool sculpt_check_boundary_vertex_in_base_mesh(const SculptSession *ss,
return BLI_BITMAP_TEST(ss->vertex_info.boundary,
BKE_pbvh_vertex_index_to_table(ss->pbvh, index));
}
static void faces_update_boundary_flags(const SculptSession *ss, const SculptVertRef vertex)
{
BKE_pbvh_update_vert_boundary_faces(ss->face_sets,
ss->mvert,
ss->medge,
ss->mloop,
ss->mpoly,
ss->mdyntopo_verts,
ss->pmap,
vertex);
// have to handle boundary here
MDynTopoVert *mv = ss->mdyntopo_verts + vertex.i;
if (sculpt_check_boundary_vertex_in_base_mesh(ss, vertex)) {
mv->flag |= DYNVERT_BOUNDARY;
if (ss->pmap[vertex.i].count < 4) {
mv->flag |= DYNVERT_CORNER;
}
}
}
SculptCornerType SCULPT_vertex_is_corner(const SculptSession *ss,
const SculptVertRef vertex,
SculptCornerType cornertype)
{
bool check_facesets = cornertype & SCULPT_CORNER_FACE_SET;
SculptCornerType ret = 0;
MDynTopoVert *mv = NULL;
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_BMESH: {
BMVert *v = (BMVert *)vertex.i;
MDynTopoVert *mv = BKE_PBVH_DYNVERT(ss->cd_dyn_vert, v);
mv = BKE_PBVH_DYNVERT(ss->cd_dyn_vert, v);
if (mv->flag & DYNVERT_NEED_BOUNDARY) {
BKE_pbvh_update_vert_boundary(ss->cd_dyn_vert,
@ -2150,36 +2182,13 @@ SculptCornerType SCULPT_vertex_is_corner(const SculptSession *ss,
ss->boundary_symmetry);
}
ret = 0;
if (cornertype & SCULPT_CORNER_MESH) {
ret |= (mv->flag & DYNVERT_CORNER) ? SCULPT_CORNER_MESH : 0;
}
if (cornertype & SCULPT_CORNER_FACE_SET) {
ret |= (mv->flag & DYNVERT_FSET_CORNER) ? SCULPT_CORNER_FACE_SET : 0;
}
if (cornertype & SCULPT_CORNER_SEAM) {
ret |= (mv->flag & DYNVERT_SEAM_CORNER) ? SCULPT_CORNER_SEAM : 0;
}
if (cornertype & SCULPT_CORNER_SHARP) {
ret |= (mv->flag & DYNVERT_SHARP_CORNER) ? SCULPT_CORNER_SHARP : 0;
}
break;
}
case PBVH_FACES:
if (ss->pmap) {
// sculpt_check_corner_face_set_in_base_mesh
ret = sculpt_check_corner_in_base_mesh(ss, vertex, check_facesets);
}
else {
// approximate
if (SCULPT_vertex_is_boundary(ss, vertex, SCULPT_BOUNDARY_MESH) &&
SCULPT_vertex_valence_get(ss, vertex) < 4) {
ret = SCULPT_CORNER_MESH;
}
mv = ss->mdyntopo_verts + vertex.i;
// can't check face sets in this case
if (mv->flag & DYNVERT_NEED_BOUNDARY) {
faces_update_boundary_flags(ss, vertex);
}
break;
case PBVH_GRIDS: {
@ -2199,11 +2208,27 @@ SculptCornerType SCULPT_vertex_is_corner(const SculptSession *ss,
return false; // sculpt_check_unique_face_set_for_edge_in_base_mesh(ss, v1, v2);
case SUBDIV_CCG_ADJACENT_NONE:
return false;
break;
}
return 0;
}
}
ret = 0;
if (cornertype & SCULPT_CORNER_MESH) {
ret |= (mv->flag & DYNVERT_CORNER) ? SCULPT_CORNER_MESH : 0;
}
if (cornertype & SCULPT_CORNER_FACE_SET) {
ret |= (mv->flag & DYNVERT_FSET_CORNER) ? SCULPT_CORNER_FACE_SET : 0;
}
if (cornertype & SCULPT_CORNER_SEAM) {
ret |= (mv->flag & DYNVERT_SEAM_CORNER) ? SCULPT_CORNER_SEAM : 0;
}
if (cornertype & SCULPT_CORNER_SHARP) {
ret |= (mv->flag & DYNVERT_SHARP_CORNER) ? SCULPT_CORNER_SHARP : 0;
}
return ret;
}
@ -2212,10 +2237,11 @@ SculptBoundaryType SCULPT_vertex_is_boundary(const SculptSession *ss,
SculptBoundaryType boundary_types)
{
bool check_facesets = boundary_types & SCULPT_BOUNDARY_FACE_SET;
MDynTopoVert *mv = NULL;
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_BMESH: {
MDynTopoVert *mv = BKE_PBVH_DYNVERT(ss->cd_dyn_vert, ((BMVert *)(vertex.i)));
mv = BKE_PBVH_DYNVERT(ss->cd_dyn_vert, ((BMVert *)(vertex.i)));
if (mv->flag & DYNVERT_NEED_BOUNDARY) {
BKE_pbvh_update_vert_boundary(ss->cd_dyn_vert,
@ -2226,47 +2252,15 @@ SculptBoundaryType SCULPT_vertex_is_boundary(const SculptSession *ss,
ss->boundary_symmetry);
}
int flag = 0;
if (boundary_types & SCULPT_BOUNDARY_MESH) {
flag |= (mv->flag & DYNVERT_BOUNDARY) ? SCULPT_BOUNDARY_MESH : 0;
}
if (boundary_types & SCULPT_BOUNDARY_FACE_SET) {
flag |= (mv->flag & DYNVERT_FSET_BOUNDARY) ? SCULPT_BOUNDARY_FACE_SET : 0;
}
if (boundary_types & SCULPT_BOUNDARY_SHARP) {
flag |= (mv->flag & DYNVERT_SHARP_BOUNDARY) ? SCULPT_BOUNDARY_SHARP : 0;
}
if (boundary_types & SCULPT_BOUNDARY_SEAM) {
flag |= (mv->flag & DYNVERT_SEAM_BOUNDARY) ? SCULPT_BOUNDARY_SEAM : 0;
}
return flag;
break;
}
case PBVH_FACES: {
int flag = 0;
mv = ss->mdyntopo_verts + vertex.i;
if (!SCULPT_vertex_all_face_sets_visible_get(ss, vertex)) {
flag |= SCULPT_BOUNDARY_MESH;
if (mv->flag & DYNVERT_NEED_BOUNDARY) {
faces_update_boundary_flags(ss, vertex);
}
if (check_facesets) {
bool ret = sculpt_check_boundary_vertex_in_base_mesh(ss, vertex);
if (ret) {
flag |= SCULPT_BOUNDARY_MESH;
}
if (!SCULPT_vertex_has_unique_face_set(ss, vertex)) {
flag |= SCULPT_BOUNDARY_FACE_SET;
}
return flag;
}
else if (sculpt_check_boundary_vertex_in_base_mesh(ss, vertex)) {
return SCULPT_BOUNDARY_MESH;
}
return 0;
break;
}
case PBVH_GRIDS: {
@ -2296,6 +2290,21 @@ SculptBoundaryType SCULPT_vertex_is_boundary(const SculptSession *ss,
}
}
int flag = 0;
if (boundary_types & SCULPT_BOUNDARY_MESH) {
flag |= (mv->flag & DYNVERT_BOUNDARY) ? SCULPT_BOUNDARY_MESH : 0;
}
if (boundary_types & SCULPT_BOUNDARY_FACE_SET) {
flag |= (mv->flag & DYNVERT_FSET_BOUNDARY) ? SCULPT_BOUNDARY_FACE_SET : 0;
}
if (boundary_types & SCULPT_BOUNDARY_SHARP) {
flag |= (mv->flag & DYNVERT_SHARP_BOUNDARY) ? SCULPT_BOUNDARY_SHARP : 0;
}
if (boundary_types & SCULPT_BOUNDARY_SEAM) {
flag |= (mv->flag & DYNVERT_SEAM_BOUNDARY) ? SCULPT_BOUNDARY_SEAM : 0;
}
return flag;
return 0;
}
@ -7417,6 +7426,8 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata,
}
}
BKE_pbvh_vertex_iter_end;
BKE_pbvh_node_mark_update(data->nodes[n]);
}
static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
@ -8702,7 +8713,7 @@ void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings
return;
}
if (brush->sculpt_tool == SCULPT_TOOL_ARRAY && type != PBVH_FACES) {
if (brush->sculpt_tool == SCULPT_TOOL_ARRAY && !ELEM(type, PBVH_FACES, PBVH_BMESH)) {
return;
}
@ -8787,7 +8798,7 @@ void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings
BKE_pbvh_node_mark_update(nodes[i]);
}
}
else {
else if (brush->sculpt_tool != SCULPT_TOOL_ARRAY) {
for (int i = 0; i < totnode; i++) {
SCULPT_ensure_dyntopo_node_undo(ob, nodes[i], SCULPT_UNDO_COORDS, -1);
@ -9162,7 +9173,7 @@ static void SCULPT_run_command_list(
return;
}
if (brush->sculpt_tool == SCULPT_TOOL_ARRAY && type != PBVH_FACES) {
if (brush->sculpt_tool == SCULPT_TOOL_ARRAY && !ELEM(type, PBVH_FACES, PBVH_BMESH)) {
return;
}
@ -9346,6 +9357,11 @@ static void SCULPT_run_command_list(
ss->cache->bstrength = brush_strength(
sd, ss->cache, calc_symmetry_feather(sd, ss->cache), ups);
if (!BRUSHSET_GET_INT(cmd->params_mapped, use_ctrl_invert, NULL)) {
ss->cache->bstrength = fabsf(ss->cache->bstrength);
}
brush2->alpha = fabs(ss->cache->bstrength);
// printf("brush2->alpha: %f\n", brush2->alpha);
@ -10892,6 +10908,8 @@ static bool sculpt_needs_connectivity_info(Sculpt *sd,
SculptSession *ss,
int stroke_mode)
{
return true;
#if 0
if (ss && ss->pbvh && SCULPT_is_automasking_enabled(sd, ss, brush)) {
return true;
}
@ -10909,6 +10927,7 @@ static bool sculpt_needs_connectivity_info(Sculpt *sd,
(brush->sculpt_tool == SCULPT_TOOL_CLOTH) || (brush->sculpt_tool == SCULPT_TOOL_SMEAR) ||
(brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS) ||
(brush->sculpt_tool == SCULPT_TOOL_DISPLACEMENT_SMEAR));
#endif
}
void SCULPT_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush)
@ -13952,20 +13971,20 @@ int SCULPT_vertex_valence_get(const struct SculptSession *ss, SculptVertRef vert
}
#endif
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
tot++;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
MDynTopoVert *mv = ss->mdyntopo_verts + vertex.i;
#ifdef NDEBUG
if (mval >= 0 && mval != tot) {
printf("Out of date vertex valence detected! old: %d, should be: %d\n", mval, tot);
}
#else
BLI_assert(mval < 0 || mval == tot);
#endif
if (mv->flag & DYNVERT_NEED_VALENCE) {
mv->flag &= ~DYNVERT_NEED_VALENCE;
return tot;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
tot++;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
mv->valence = tot;
}
return mv->valence;
}
typedef struct BMLinkItem {

View File

@ -82,20 +82,59 @@ static void sculpt_vertex_array_data_get(SculptArray *array,
*r_symmetry_pass = array->symmetry_pass[vertex];
}
static void sculpt_array_datalayers_add(Mesh *mesh)
static void sculpt_array_datalayers_init(SculptArray *array, SculptSession *ss)
{
int *v_array_instance = CustomData_add_layer_named(
&mesh->vdata, CD_PROP_INT32, CD_CALLOC, NULL, mesh->totvert, array_instance_cd_name);
for (int i = 0; i < mesh->totvert; i++) {
v_array_instance[i] = ARRAY_INSTANCE_ORIGINAL;
SculptLayerParams params = {.permanent = true, .simple_array = false};
if (!array->scl_inst) {
array->scl_inst = MEM_callocN(sizeof(SculptCustomLayer), __func__);
}
CustomData_add_layer_named(
&mesh->vdata, CD_PROP_INT32, CD_CALLOC, NULL, mesh->totvert, array_symmetry_pass_cd_name);
if (!array->scl_sym) {
array->scl_sym = MEM_callocN(sizeof(SculptCustomLayer), __func__);
}
SCULPT_temp_customlayer_ensure(
ss, ATTR_DOMAIN_POINT, CD_PROP_INT32, array_instance_cd_name, &params);
SCULPT_temp_customlayer_get(
ss, ATTR_DOMAIN_POINT, CD_PROP_INT32, array_instance_cd_name, array->scl_inst, &params);
SCULPT_temp_customlayer_ensure(
ss, ATTR_DOMAIN_POINT, CD_PROP_INT32, array_symmetry_pass_cd_name, &params);
SCULPT_temp_customlayer_get(
ss, ATTR_DOMAIN_POINT, CD_PROP_INT32, array_symmetry_pass_cd_name, array->scl_sym, &params);
}
void SCULPT_array_datalayers_free(Object *ob)
static void sculpt_array_datalayers_add(SculptArray *array, SculptSession *ss, Mesh *mesh)
{
// int *v_array_instance = CustomData_add_layer_named(
// &mesh->vdata, CD_PROP_INT32, CD_CALLOC, NULL, mesh->totvert, array_instance_cd_name);
int totvert = SCULPT_vertex_count_get(ss);
const SculptCustomLayer *scl = array->scl_inst;
for (int i = 0; i < totvert; i++) {
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
*(int *)SCULPT_temp_cdata_get(vertex, scl) = ARRAY_INSTANCE_ORIGINAL;
}
}
ATTR_NO_OPT void SCULPT_array_datalayers_free(SculptArray *array, Object *ob)
{
SculptSession *ss = ob->sculpt;
if (array->scl_inst) {
SCULPT_temp_customlayer_release(ss, array->scl_inst);
}
if (array->scl_sym) {
SCULPT_temp_customlayer_release(ss, array->scl_sym);
}
array->scl_inst = NULL;
array->scl_sym = NULL;
return;
Mesh *mesh = BKE_object_get_original_mesh(ob);
int v_layer_index = CustomData_get_named_layer_index(
&mesh->vdata, CD_PROP_INT32, array_instance_cd_name);
@ -114,21 +153,39 @@ const float source_geometry_threshold = 0.5f;
static BMesh *sculpt_array_source_build(Object *ob, Brush *brush, SculptArray *array)
{
bool have_bmesh = ob->sculpt->bm && ob->sculpt->pbvh &&
BKE_pbvh_type(ob->sculpt->pbvh) == PBVH_BMESH;
Mesh *sculpt_mesh = BKE_object_get_original_mesh(ob);
BMesh *srcbm;
const BMAllocTemplate allocsizea = BMALLOC_TEMPLATE_FROM_ME(sculpt_mesh);
srcbm = BM_mesh_create(&allocsizea,
&((struct BMeshCreateParams){
.use_toolflags = true,
}));
BM_mesh_bm_from_me(NULL,
srcbm,
sculpt_mesh,
&((struct BMeshFromMeshParams){
.calc_face_normal = true,
}));
BMesh *BM_mesh_copy_ex(BMesh * bm_old, struct BMeshCreateParams * params);
if (have_bmesh) {
srcbm = BM_mesh_copy_ex(
ob->sculpt->bm,
&((struct BMeshCreateParams){.use_toolflags = true,
.id_map = false,
.id_elem_mask = ob->sculpt->bm->idmap.flag &
(BM_VERT | BM_EDGE | BM_FACE | BM_LOOP),
.create_unique_ids = true,
.copy_all_layers = true}));
}
else {
const BMAllocTemplate allocsizea = BMALLOC_TEMPLATE_FROM_ME(sculpt_mesh);
srcbm = BM_mesh_create(&allocsizea,
&((struct BMeshCreateParams){
.use_toolflags = true,
}));
BM_mesh_bm_from_me(NULL,
srcbm,
sculpt_mesh,
&((struct BMeshFromMeshParams){
.calc_face_normal = true,
}));
}
BM_mesh_elem_table_ensure(srcbm, BM_VERT);
BM_mesh_elem_index_ensure(srcbm, BM_VERT);
@ -186,7 +243,9 @@ static BMesh *sculpt_array_source_build(Object *ob, Brush *brush, SculptArray *a
return srcbm;
}
void sculpt_array_source_datalayer_update(BMesh *bm, const int symm_pass, const int copy_index)
ATTR_NO_OPT void sculpt_array_source_datalayer_update(BMesh *bm,
const int symm_pass,
const int copy_index)
{
const int cd_array_instance_index = CustomData_get_named_layer_index(
&bm->vdata, CD_PROP_INT32, array_instance_cd_name);
@ -216,7 +275,6 @@ static void sculpt_array_final_mesh_write(Object *ob, BMesh *final_mesh)
Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(final_mesh, NULL, sculpt_mesh);
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
BKE_mesh_nomain_to_mesh(result, ob->data, ob, &CD_MASK_MESH, true);
BKE_id_free(NULL, result);
BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
const int next_face_set_id = ED_sculpt_face_sets_find_next_available_id(ob->data);
@ -225,61 +283,70 @@ static void sculpt_array_final_mesh_write(Object *ob, BMesh *final_mesh)
ss->needs_pbvh_rebuild = true;
}
static void sculpt_array_ensure_geometry_indices(Object *ob, SculptArray *array)
ATTR_NO_OPT static void sculpt_array_ensure_geometry_indices(Object *ob, SculptArray *array)
{
Mesh *mesh = BKE_object_get_original_mesh(ob);
if (array->copy_index) {
return;
}
printf("ALLOCATION COPY INDEX\n");
array->copy_index = MEM_malloc_arrayN(mesh->totvert, sizeof(int), "array copy index");
array->symmetry_pass = MEM_malloc_arrayN(
mesh->totvert, sizeof(int), "array symmetry pass index");
SculptSession *ss = ob->sculpt;
int totvert = SCULPT_vertex_count_get(ss);
int *cd_array_instance = CustomData_get_layer_named(
&mesh->vdata, CD_PROP_INT32, array_instance_cd_name);
array->copy_index = MEM_malloc_arrayN(totvert, sizeof(int), "array copy index");
array->symmetry_pass = MEM_malloc_arrayN(totvert, sizeof(int), "array symmetry pass index");
int *cd_array_symm_pass = CustomData_get_layer_named(
&mesh->vdata, CD_PROP_INT32, array_symmetry_pass_cd_name);
for (int i = 0; i < totvert; i++) {
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
if (!cd_array_instance) {
printf("ERROR 1");
array->copy_index[i] = *(int *)SCULPT_temp_cdata_get(vertex, array->scl_inst);
array->symmetry_pass[i] = *(int *)SCULPT_temp_cdata_get(vertex, array->scl_sym);
}
for (int i = 0; i < mesh->totvert; i++) {
array->copy_index[i] = cd_array_instance[i];
array->symmetry_pass[i] = cd_array_symm_pass[i];
}
SCULPT_array_datalayers_free(ob);
SCULPT_array_datalayers_free(array, ob);
}
static void sculpt_array_mesh_build(Sculpt *sd, Object *ob, SculptArray *array)
ATTR_NO_OPT static void sculpt_array_mesh_build(Sculpt *sd, Object *ob, SculptArray *array)
{
bool have_bmesh = ob->sculpt->bm && ob->sculpt->pbvh &&
BKE_pbvh_type(ob->sculpt->pbvh) == PBVH_BMESH;
Mesh *sculpt_mesh = BKE_object_get_original_mesh(ob);
Brush *brush = BKE_paint_brush(&sd->paint);
sculpt_array_datalayers_add(sculpt_mesh);
sculpt_array_datalayers_init(array, ob->sculpt);
sculpt_array_datalayers_add(array, ob->sculpt, sculpt_mesh);
BMesh *srcbm = sculpt_array_source_build(ob, brush, array);
BMesh *destbm;
const BMAllocTemplate allocsizeb = BMALLOC_TEMPLATE_FROM_ME(sculpt_mesh);
destbm = BM_mesh_create(&allocsizeb,
&((struct BMeshCreateParams){
.use_toolflags = true,
}));
BM_mesh_bm_from_me(NULL,
destbm,
sculpt_mesh,
&((struct BMeshFromMeshParams){
.calc_face_normal = true,
}));
if (!have_bmesh) {
destbm = BM_mesh_create(&allocsizeb,
&((struct BMeshCreateParams){
.use_toolflags = true,
}));
BM_mesh_bm_from_me(NULL,
destbm,
sculpt_mesh,
&((struct BMeshFromMeshParams){
.calc_face_normal = true,
}));
}
else {
destbm = ob->sculpt->bm;
}
BM_mesh_toolflags_set(destbm, true);
BM_mesh_toolflags_set(srcbm, true);
BM_mesh_elem_toolflags_ensure(destbm);
BM_mesh_elem_toolflags_ensure(srcbm);
const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
for (char symm_it = 0; symm_it <= symm; symm_it++) {
if (!SCULPT_is_symmetry_iteration_valid(symm_it, symm)) {
@ -289,16 +356,25 @@ static void sculpt_array_mesh_build(Sculpt *sd, Object *ob, SculptArray *array)
for (int copy_index = 0; copy_index < array->num_copies; copy_index++) {
sculpt_array_source_datalayer_update(srcbm, symm_it, copy_index);
BM_mesh_copy_init_customdata(destbm, srcbm, &bm_mesh_allocsize_default);
if (1) { //! have_bmesh) {
// BM_mesh_copy_init_customdata(destbm, srcbm, &bm_mesh_allocsize_default);
}
const int opflag = (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE);
BMO_op_callf(srcbm, opflag, "duplicate geom=%avef dest=%p", destbm);
}
}
sculpt_array_final_mesh_write(ob, destbm);
if (!have_bmesh) {
sculpt_array_final_mesh_write(ob, destbm);
BM_mesh_free(destbm);
}
else {
SCULPT_update_customdata_refs(ob->sculpt);
ob->sculpt->needs_pbvh_rebuild = true;
}
BM_mesh_free(srcbm);
BM_mesh_free(destbm);
}
static SculptArray *sculpt_array_cache_create(Object *ob,
@ -532,9 +608,9 @@ static void sculpt_array_update(Object *ob, Brush *brush, SculptArray *array)
}
}
static void do_array_deform_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
ATTR_NO_OPT static void do_array_deform_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
@ -696,7 +772,8 @@ static void sculpt_array_ensure_original_coordinates(Object *ob, SculptArray *ar
return;
}
array->orco = MEM_malloc_arrayN(sculpt_mesh->totvert, sizeof(float) * 3, "array orco");
array->orco = MEM_malloc_arrayN(totvert, sizeof(float) * 3, "array orco");
for (int i = 0; i < totvert; i++) {
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
@ -788,7 +865,7 @@ static void sculpt_array_stroke_sample_add(Object *ob, SculptArray *array)
array->path.tot_points++;
}
void SCULPT_do_array_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
ATTR_NO_OPT void SCULPT_do_array_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
@ -947,6 +1024,8 @@ void SCULPT_do_array_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
return;
}
SCULPT_vertex_random_access_ensure(ss);
sculpt_array_ensure_base_transform(sd, ob, ss->array);
sculpt_array_ensure_original_coordinates(ob, ss->array);
sculpt_array_ensure_geometry_indices(ob, ss->array);

View File

@ -928,7 +928,8 @@ static void cloth_sort_constraints_for_tasks(SculptSession *ss,
SculptClothTaskData *tasks = MEM_calloc_arrayN(
totthread + 1, sizeof(SculptClothTaskData), "SculptClothTaskData");
int *vthreads = MEM_calloc_arrayN(ss->totvert, sizeof(*vthreads), "cloth vthreads");
int *vthreads = MEM_calloc_arrayN(
SCULPT_vertex_count_get(ss), sizeof(*vthreads), "cloth vthreads");
SculptClothLengthConstraint *cons = cloth_sim->length_constraints, *con;
int totcon = cloth_sim->tot_length_constraints;