diff options
-rw-r--r-- | source/blender/blenkernel/BKE_customdata.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_paint.h | 164 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_pbvh.h | 4 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/customdata.cc | 5 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/paint.cc | 607 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/pbvh.c | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/pbvh_bmesh.c | 10 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt.c | 11 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_automasking.cc | 73 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_brush_types.c | 4 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_dyntopo.c | 45 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_intern.h | 9 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_ops.c | 23 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_undo.c | 2 |
14 files changed, 845 insertions, 117 deletions
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index 24fa5f0e87a..0f5123573f7 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -740,6 +740,8 @@ void CustomData_blend_write(BlendWriter *writer, void CustomData_blend_read(struct BlendDataReader *reader, struct CustomData *data, int count); +size_t CustomData_get_elem_size(struct CustomDataLayer *layer); + #ifndef NDEBUG struct DynStr; /** Use to inspect mesh data when debugging. */ diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 774765c3ca1..9b28b6380b0 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -8,7 +8,9 @@ */ #include "BLI_bitmap.h" +#include "BLI_compiler_compat.h" #include "BLI_utildefines.h" + #include "DNA_brush_enums.h" #include "DNA_object_enums.h" @@ -485,6 +487,74 @@ typedef struct SculptFakeNeighbors { /* Session data (mode-specific) */ +/* Custom Temporary Attributes */ + +typedef struct SculptAttributeParams { + /* Allocate a flat array outside the CustomData system. Cannot be combined with permanent. */ + int simple_array : 1; + + /* Do not mark CustomData layer as temporary. Cannot be combined with simple_array. Doesn't + * work with PBVH_GRIDS. + */ + int permanent : 1; /* Cannot be combined with simple_array. */ + int stroke_only : 1; /* Release layer at end of struct */ +} SculptAttributeParams; + +typedef struct SculptAttribute { + /* Domain, data type and name */ + eAttrDomain domain; + eCustomDataType proptype; + char name[MAX_CUSTOMDATA_LAYER_NAME]; + + /* Source layer on mesh/bmesh, if any. */ + struct CustomDataLayer *layer; + + /* Data stored as flat array. */ + void *data; + int elem_size, elem_num; + bool data_for_bmesh; /* Temporary data store as array outside of bmesh. */ + + /* Data stored per BMesh element. */ + int bmesh_cd_offset; + + /* Sculpt usage */ + SculptAttributeParams params; + + /* Used to keep track of which preallocated SculptAttribute instances + * inside of SculptSession.temp_attribute are used. + */ + bool used; +} SculptAttribute; + +#define SCULPT_MAX_ATTRIBUTES 64 + +/* Get a standard attribute name. Key must match up with a member + * of SculptAttributePointers. + */ + +#define SCULPT_ATTRIBUTE_NAME(key) \ + (offsetof(SculptAttributePointers, key) >= 0 ? /* Spellcheck name. */ \ + (".sculpt_" #key) /* Make name. */ \ + : \ + "You misspelled the layer name key") + +/* Convienence pointers for standard sculpt attributes. */ + +typedef struct SculptAttributePointers { + /* Persistent base. */ + SculptAttribute *persistent_co; + SculptAttribute *persistent_no; + SculptAttribute *persistent_disp; + + /* Precomputed auto-mask factor indexed by vertex, owned by the auto-masking system and + * initialized in #SCULPT_automasking_cache_init when needed. */ + SculptAttribute *automasking_factor; + + /* BMesh */ + SculptAttribute *dyntopo_node_id_vertex; + SculptAttribute *dyntopo_node_id_face; +} SculptAttributePointers; + typedef struct SculptSession { /* Mesh data (not copied) can come either directly from a Mesh, or from a MultiresDM */ struct { /* Special handling for multires meshes */ @@ -529,6 +599,7 @@ typedef struct SculptSession { /* Mesh Face Sets */ /* Total number of polys of the base mesh. */ int totfaces; + /* The 0 ID is not used by the tools or the visibility system, it is just used when creating new * geometry (the trim tool, for example) to detect which geometry was just added, so it can be * assigned a valid Face Set after creation. Tools are not intended to run with Face Sets IDs set @@ -542,8 +613,6 @@ typedef struct SculptSession { /* BMesh for dynamic topology sculpting */ struct BMesh *bm; - int cd_vert_node_offset; - int cd_face_node_offset; bool bm_smooth_shading; /* Undo/redo log for dynamic topology sculpting */ struct BMLog *bm_log; @@ -575,7 +644,8 @@ typedef struct SculptSession { int active_face_index; int active_grid_index; - /* When active, the cursor draws with faded colors, indicating that there is an action enabled. + /* When active, the cursor draws with faded colors, indicating that there is an action + * enabled. */ bool draw_faded_cursor; float cursor_radius; @@ -584,8 +654,10 @@ typedef struct SculptSession { float cursor_sampled_normal[3]; float cursor_view_normal[3]; - /* For Sculpt trimming gesture tools, initial ray-cast data from the position of the mouse when - * the gesture starts (intersection with the surface and if they ray hit the surface or not). */ + /* For Sculpt trimming gesture tools, initial ray-cast data from the position of the mouse + * when + * the gesture starts (intersection with the surface and if they ray hit the surface or not). + */ float gesture_initial_location[3]; float gesture_initial_normal[3]; bool gesture_initial_hit; @@ -606,10 +678,6 @@ typedef struct SculptSession { /* Boundary Brush Preview */ SculptBoundary *boundary_preview; - /* Mesh State Persistence */ - /* This is freed with the PBVH, so it is always in sync with the mesh. */ - SculptPersistentBase *persistent_base; - SculptVertexInfo vertex_info; SculptFakeNeighbors fake_neighbors; @@ -655,6 +723,14 @@ typedef struct SculptSession { */ char needs_flush_to_id; + /* This is a fixed-size array so we can pass pointers to its elements + * to client code. This is important to keep bmesh offsets up to date. + */ + struct SculptAttribute temp_attributes[SCULPT_MAX_ATTRIBUTES]; + + /* Convienence SculptAttribute pointers. */ + SculptAttributePointers attrs; + /** * Some tools follows the shading chosen by the last used tool canvas. * When not set the viewport shading color would be used. @@ -675,6 +751,75 @@ void BKE_sculptsession_free_deformMats(struct SculptSession *ss); void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss); void BKE_sculptsession_bm_to_me(struct Object *ob, bool reorder); void BKE_sculptsession_bm_to_me_for_render(struct Object *object); +int BKE_sculptsession_vertex_count(const SculptSession *ss); + +/* Ensure an attribute layer exists.*/ +SculptAttribute *BKE_sculpt_attribute_ensure(struct Object *ob, + eAttrDomain domain, + eCustomDataType proptype, + const char *name, + const SculptAttributeParams *params); + +/* Returns nullptr if attribute does not exist. */ +SculptAttribute *BKE_sculpt_attribute_get(struct Object *ob, + eAttrDomain domain, + eCustomDataType proptype, + const char *name); + +bool BKE_sculpt_attribute_exists(struct Object *ob, + eAttrDomain domain, + eCustomDataType proptype, + const char *name); + +bool BKE_sculpt_attribute_destroy(struct Object *ob, SculptAttribute *attr); + +/* Destroy all attributes and psuedo-attributes created by sculpt mode.*/ +void BKE_sculpt_attribute_destroy_temporary_all(struct Object *ob); + +/* Destroy attributes that were marked as stroke only in SculptAttributeParams. */ +void BKE_sculpt_attributes_destroy_temporary_stroke(struct Object *ob); + +BLI_INLINE void *BKE_sculpt_vertex_attr_get(const PBVHVertRef vertex, const SculptAttribute *attr) +{ + if (attr->data) { + char *p = (char *)attr->data; + int idx = (int)vertex.i; + + if (attr->data_for_bmesh) { + BMElem *v = (BMElem *)vertex.i; + idx = v->head.index; + } + + return p + attr->elem_size * (int)idx; + } + else { + BMElem *v = (BMElem *)vertex.i; + return BM_ELEM_CD_GET_VOID_P(v, attr->bmesh_cd_offset); + } + + return NULL; +} + +BLI_INLINE void *BKE_sculpt_face_attr_get(const PBVHFaceRef vertex, const SculptAttribute *attr) +{ + if (attr->data) { + char *p = (char *)attr->data; + int idx = (int)vertex.i; + + if (attr->data_for_bmesh) { + BMElem *v = (BMElem *)vertex.i; + idx = v->head.index; + } + + return p + attr->elem_size * (int)idx; + } + else { + BMElem *v = (BMElem *)vertex.i; + return BM_ELEM_CD_GET_VOID_P(v, attr->bmesh_cd_offset); + } + + return NULL; +} /** * Create new color layer on object if it doesn't have one and if experimental feature set has @@ -713,6 +858,7 @@ struct PBVH *BKE_sculpt_object_pbvh_ensure(struct Depsgraph *depsgraph, struct O void BKE_sculpt_bvh_update_from_ccg(struct PBVH *pbvh, struct SubdivCCG *subdiv_ccg); +void BKE_sculpt_ensure_orig_mesh_data(struct Scene *scene, struct Object *object); void BKE_sculpt_sync_face_visibility_to_grids(struct Mesh *mesh, struct SubdivCCG *subdiv_ccg); /** diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index c32645e9ce7..ff2140732cc 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -230,7 +230,7 @@ typedef void (*BKE_pbvh_SearchNearestCallback)(PBVHNode *node, void *data, float /* Building */ -PBVH *BKE_pbvh_new(void); +PBVH *BKE_pbvh_new(PBVHType type); /** * Do a full rebuild with on Mesh data structure. * @@ -268,6 +268,8 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh, int cd_vert_node_offset, int cd_face_node_offset); +void BKE_pbvh_update_bmesh_offsets(PBVH *pbvh, int cd_vert_node_offset, int cd_face_node_offset); + void BKE_pbvh_build_pixels(PBVH *pbvh, struct Mesh *mesh, struct Image *image, diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index 64e2d00dc1b..0589e1ef8c7 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -5546,3 +5546,8 @@ eCustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type) /** \} */ } // namespace blender::bke + +size_t CustomData_get_elem_size(CustomDataLayer *layer) +{ + return LAYERTYPEINFO[layer->type].size; +} diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc index ea1bd3c1cc3..22f5b4d54c6 100644 --- a/source/blender/blenkernel/intern/paint.cc +++ b/source/blender/blenkernel/intern/paint.cc @@ -25,6 +25,7 @@ #include "BLI_hash.h" #include "BLI_listbase.h" #include "BLI_math_vector.h" +#include "BLI_string_utf8.h" #include "BLI_utildefines.h" #include "BLT_translation.h" @@ -65,6 +66,16 @@ #include "bmesh.h" +static void sculpt_attribute_update_refs(Object *ob); +static SculptAttribute *sculpt_attribute_ensure_ex(Object *ob, + eAttrDomain domain, + eCustomDataType proptype, + const char *name, + const SculptAttributeParams *params, + PBVHType pbvhtype, + bool flat_array_for_bmesh); +void sculptsession_bmesh_add_layers(Object *ob); + using blender::MutableSpan; using blender::Span; @@ -1430,13 +1441,9 @@ static void sculptsession_free_pbvh(Object *object) MEM_SAFE_FREE(ss->vemap); MEM_SAFE_FREE(ss->vemap_mem); - MEM_SAFE_FREE(ss->persistent_base); - MEM_SAFE_FREE(ss->preview_vert_list); ss->preview_vert_count = 0; - MEM_SAFE_FREE(ss->preview_vert_list); - MEM_SAFE_FREE(ss->vertex_info.connected_component); MEM_SAFE_FREE(ss->vertex_info.boundary); @@ -1470,6 +1477,8 @@ void BKE_sculptsession_free(Object *ob) if (ob && ob->sculpt) { SculptSession *ss = ob->sculpt; + BKE_sculpt_attribute_destroy_temporary_all(ob); + if (ss->bm) { BKE_sculptsession_bm_to_me(ob, true); BM_mesh_free(ss->bm); @@ -1628,6 +1637,21 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob) return false; } +/* Helper function to keep persistent base attribute references up to + * date. This is a bit more tricky since they persist across strokes. + */ +static void sculpt_update_persistent_base(Object *ob) +{ + SculptSession *ss = ob->sculpt; + + ss->attrs.persistent_co = BKE_sculpt_attribute_get( + ob, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, SCULPT_ATTRIBUTE_NAME(persistent_co)); + ss->attrs.persistent_no = BKE_sculpt_attribute_get( + ob, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, SCULPT_ATTRIBUTE_NAME(persistent_no)); + ss->attrs.persistent_disp = BKE_sculpt_attribute_get( + ob, ATTR_DOMAIN_POINT, CD_PROP_FLOAT, SCULPT_ATTRIBUTE_NAME(persistent_disp)); +} + static void sculpt_update_object( Depsgraph *depsgraph, Object *ob, Object *ob_eval, bool need_pmap, bool is_paint_tool) { @@ -1726,6 +1750,9 @@ static void sculpt_update_object( BKE_pbvh_face_sets_color_set(ss->pbvh, me->face_sets_color_seed, me->face_sets_color_default); + sculpt_attribute_update_refs(ob); + sculpt_update_persistent_base(ob); + if (need_pmap && ob->type == OB_MESH && !ss->pmap) { BKE_mesh_vert_poly_map_create(&ss->pmap, &ss->pmap_mem, @@ -2119,13 +2146,16 @@ void BKE_sculpt_sync_face_visibility_to_grids(Mesh *mesh, SubdivCCG *subdiv_ccg) static PBVH *build_pbvh_for_dynamic_topology(Object *ob) { - PBVH *pbvh = BKE_pbvh_new(); + PBVH *pbvh = ob->sculpt->pbvh = BKE_pbvh_new(PBVH_BMESH); + + sculptsession_bmesh_add_layers(ob); + BKE_pbvh_build_bmesh(pbvh, ob->sculpt->bm, ob->sculpt->bm_smooth_shading, ob->sculpt->bm_log, - ob->sculpt->cd_vert_node_offset, - ob->sculpt->cd_face_node_offset); + ob->sculpt->attrs.dyntopo_node_id_vertex->bmesh_cd_offset, + ob->sculpt->attrs.dyntopo_node_id_face->bmesh_cd_offset); pbvh_show_mask_set(pbvh, ob->sculpt->show_mask); pbvh_show_face_sets_set(pbvh, false); return pbvh; @@ -2135,7 +2165,7 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool { 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(); + PBVH *pbvh = BKE_pbvh_new(PBVH_FACES); BKE_pbvh_respect_hide_set(pbvh, respect_hide); MutableSpan<MVert> verts = me->verts_for_write(); @@ -2178,7 +2208,7 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect { CCGKey key; BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg); - PBVH *pbvh = BKE_pbvh_new(); + PBVH *pbvh = BKE_pbvh_new(PBVH_GRIDS); BKE_pbvh_respect_hide_set(pbvh, respect_hide); Mesh *base_mesh = BKE_mesh_from_object(ob); @@ -2288,3 +2318,562 @@ void BKE_paint_face_set_overlay_color_get(const int face_set, const int seed, uc &rgba[2]); rgba_float_to_uchar(r_color, rgba); } + +int BKE_sculptsession_vertex_count(const SculptSession *ss) +{ + switch (BKE_pbvh_type(ss->pbvh)) { + case PBVH_FACES: + return ss->totvert; + case PBVH_BMESH: + return BM_mesh_elem_count(ss->bm, BM_VERT); + case PBVH_GRIDS: + return BKE_pbvh_get_grid_num_verts(ss->pbvh); + } + + return 0; +} + +/** Returns pointer to a CustomData associated with a given domain, if + * one exists. If not nullptr is returned (this may happen with e.g. + * multires and ATTR_DOMAIN_POINT). + */ +static CustomData *sculpt_get_cdata(Object *ob, eAttrDomain domain) +{ + SculptSession *ss = ob->sculpt; + + if (ss->bm) { + switch (domain) { + case ATTR_DOMAIN_POINT: + return &ss->bm->vdata; + case ATTR_DOMAIN_FACE: + return &ss->bm->pdata; + default: + BLI_assert_unreachable(); + return NULL; + } + } + else { + Mesh *me = BKE_object_get_original_mesh(ob); + + switch (domain) { + case ATTR_DOMAIN_POINT: + /* Cannot get vertex domain for multires grids. */ + if (ss->pbvh && BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { + return nullptr; + } + + return &me->vdata; + case ATTR_DOMAIN_FACE: + return &me->pdata; + default: + BLI_assert_unreachable(); + return NULL; + } + } +} + +static int sculpt_attr_elem_count_get(Object *ob, eAttrDomain domain) +{ + SculptSession *ss = ob->sculpt; + + switch (domain) { + case ATTR_DOMAIN_POINT: + return BKE_sculptsession_vertex_count(ss); + break; + case ATTR_DOMAIN_FACE: + return ss->totfaces; + break; + default: + BLI_assert_unreachable(); + return 0; + } +} + +static bool sculpt_attribute_create(SculptSession *ss, + Object *ob, + eAttrDomain domain, + eCustomDataType proptype, + const char *name, + SculptAttribute *out, + const SculptAttributeParams *params, + PBVHType pbvhtype, + bool flat_array_for_bmesh) +{ + Mesh *me = BKE_object_get_original_mesh(ob); + + bool simple_array = params->simple_array; + bool permanent = params->permanent; + + out->params = *params; + out->proptype = proptype; + out->domain = domain; + BLI_strncpy_utf8(out->name, name, sizeof(out->name)); + + /* Force non-CustomData simple_array mode if not PBVH_FACES. */ + if (pbvhtype == PBVH_GRIDS || (pbvhtype == PBVH_BMESH && flat_array_for_bmesh)) { + if (permanent) { + printf( + "%s: error: tried to make permanent customdata in multires or bmesh mode; will make " + "local " + "array " + "instead.\n", + __func__); + permanent = out->params.permanent = false; + } + + simple_array = out->params.simple_array = true; + } + + BLI_assert(!(simple_array && permanent)); + + int totelem = sculpt_attr_elem_count_get(ob, domain); + + if (simple_array) { + int elemsize = CustomData_sizeof(proptype); + + out->data = MEM_calloc_arrayN(totelem, elemsize, __func__); + + out->data_for_bmesh = ss->bm != NULL; + out->bmesh_cd_offset = -1; + out->layer = NULL; + out->elem_size = elemsize; + out->used = true; + out->elem_num = totelem; + + return true; + } + + switch (BKE_pbvh_type(ss->pbvh)) { + case PBVH_BMESH: { + CustomData *cdata = NULL; + out->data_for_bmesh = true; + + switch (domain) { + case ATTR_DOMAIN_POINT: + cdata = &ss->bm->vdata; + break; + case ATTR_DOMAIN_FACE: + cdata = &ss->bm->pdata; + break; + default: + out->used = false; + return false; + } + + BLI_assert(CustomData_get_named_layer_index(cdata, proptype, name) == -1); + + BM_data_layer_add_named(ss->bm, cdata, proptype, name); + int index = CustomData_get_named_layer_index(cdata, proptype, name); + + if (!permanent) { + cdata->layers[index].flag |= CD_FLAG_TEMPORARY | CD_FLAG_NOCOPY; + } + + out->data = NULL; + out->layer = cdata->layers + index; + out->bmesh_cd_offset = out->layer->offset; + out->elem_size = CustomData_sizeof(proptype); + break; + } + case PBVH_FACES: { + CustomData *cdata = NULL; + + out->data_for_bmesh = false; + + switch (domain) { + case ATTR_DOMAIN_POINT: + cdata = &me->vdata; + break; + case ATTR_DOMAIN_FACE: + cdata = &me->pdata; + break; + default: + out->used = false; + return false; + } + + BLI_assert(CustomData_get_named_layer_index(cdata, proptype, name) == -1); + + CustomData_add_layer_named(cdata, proptype, CD_SET_DEFAULT, NULL, totelem, name); + int index = CustomData_get_named_layer_index(cdata, proptype, name); + + if (!permanent) { + cdata->layers[index].flag |= CD_FLAG_TEMPORARY | CD_FLAG_NOCOPY; + } + + out->data = NULL; + out->layer = cdata->layers + index; + out->bmesh_cd_offset = -1; + out->data = out->layer->data; + out->elem_size = CustomData_get_elem_size(out->layer); + + break; + } + case PBVH_GRIDS: { + /* GRIDS should have been handled as simple arrays. */ + BLI_assert_unreachable(); + break; + } + default: + BLI_assert_unreachable(); + break; + } + + out->used = true; + out->elem_num = totelem; + + return true; +} + +static bool sculpt_attr_update(Object *ob, SculptAttribute *attr) +{ + SculptSession *ss = ob->sculpt; + int elem_num = sculpt_attr_elem_count_get(ob, attr->domain); + + bool bad = false; + + if (attr->params.simple_array) { + bad = attr->elem_num != elem_num; + + if (bad) { + MEM_SAFE_FREE(attr->data); + } + } + else { + CustomData *cdata = sculpt_get_cdata(ob, attr->domain); + + if (cdata) { + int layer_index = CustomData_get_named_layer_index(cdata, attr->proptype, attr->name); + + if (layer_index != -1 && attr->data_for_bmesh) { + attr->bmesh_cd_offset = cdata->layers[layer_index].offset; + } + else { + bad = true; + } + } + } + + if (bad) { + sculpt_attribute_create(ss, + ob, + attr->domain, + attr->proptype, + attr->name, + attr, + &attr->params, + BKE_pbvh_type(ss->pbvh), + true); + } + + return bad; +} + +static SculptAttribute *sculpt_get_cached_layer(SculptSession *ss, + eAttrDomain domain, + eCustomDataType proptype, + const char *name) +{ + for (int i = 0; i < SCULPT_MAX_ATTRIBUTES; i++) { + SculptAttribute *attr = ss->temp_attributes + i; + + if (attr->used && STREQ(attr->name, name) && attr->proptype == proptype && + attr->domain == domain) { + + return attr; + } + } + + return NULL; +} + +bool BKE_sculpt_attribute_exists(Object *ob, + eAttrDomain domain, + eCustomDataType proptype, + const char *name) +{ + SculptSession *ss = ob->sculpt; + SculptAttribute *attr = sculpt_get_cached_layer(ss, domain, proptype, name); + + if (attr) { + return true; + } + + CustomData *cdata = sculpt_get_cdata(ob, domain); + return CustomData_get_named_layer_index(cdata, proptype, name) != -1; + + return false; +} + +static SculptAttribute *sculpt_alloc_attr(SculptSession *ss) +{ + for (int i = 0; i < SCULPT_MAX_ATTRIBUTES; i++) { + if (!ss->temp_attributes[i].used) { + memset((void *)(ss->temp_attributes + i), 0, sizeof(SculptAttribute)); + ss->temp_attributes[i].used = true; + + return ss->temp_attributes + i; + } + } + + BLI_assert_unreachable(); + return NULL; +} + +SculptAttribute *BKE_sculpt_attribute_get(struct Object *ob, + eAttrDomain domain, + eCustomDataType proptype, + const char *name) +{ + SculptSession *ss = ob->sculpt; + + /* See if attribute is cached in ss->temp_attributes. */ + SculptAttribute *attr = sculpt_get_cached_layer(ss, domain, proptype, name); + + if (attr) { + sculpt_attr_update(ob, attr); + return attr; + } + + /* Does attribute exist in CustomData layout? */ + CustomData *cdata = sculpt_get_cdata(ob, domain); + if (cdata) { + int index = CustomData_get_named_layer_index(cdata, proptype, name); + + if (index != -1) { + int totelem = 0; + + switch (domain) { + case ATTR_DOMAIN_POINT: + totelem = BKE_sculptsession_vertex_count(ss); + break; + case ATTR_DOMAIN_FACE: + totelem = ss->totfaces; + break; + default: + BLI_assert_unreachable(); + break; + } + + attr = sculpt_alloc_attr(ss); + + attr->used = true; + attr->proptype = proptype; + attr->data = cdata->layers[index].data; + attr->bmesh_cd_offset = cdata->layers[index].offset; + attr->elem_num = totelem; + attr->layer = cdata->layers + index; + attr->elem_size = CustomData_get_elem_size(attr->layer); + + BLI_strncpy_utf8(attr->name, name, sizeof(attr->name)); + return attr; + } + } + + return NULL; +} + +static SculptAttribute *sculpt_attribute_ensure_ex(Object *ob, + eAttrDomain domain, + eCustomDataType proptype, + const char *name, + const SculptAttributeParams *params, + PBVHType pbvhtype, + bool flat_array_for_bmesh) +{ + SculptSession *ss = ob->sculpt; + SculptAttribute *attr = BKE_sculpt_attribute_get(ob, domain, proptype, name); + + if (attr) { + return attr; + } + + attr = sculpt_alloc_attr(ss); + + /* Create attribute. */ + sculpt_attribute_create( + ss, ob, domain, proptype, name, attr, params, pbvhtype, flat_array_for_bmesh); + sculpt_attribute_update_refs(ob); + + return attr; +} + +SculptAttribute *BKE_sculpt_attribute_ensure(Object *ob, + eAttrDomain domain, + eCustomDataType proptype, + const char *name, + const SculptAttributeParams *params) +{ + SculptAttributeParams temp_params = *params; + + return sculpt_attribute_ensure_ex( + ob, domain, proptype, name, &temp_params, BKE_pbvh_type(ob->sculpt->pbvh), true); +} + +static void sculptsession_bmesh_attr_update_internal(Object *ob) +{ + SculptSession *ss = ob->sculpt; + + sculptsession_bmesh_add_layers(ob); + + if (ss->pbvh) { + BKE_pbvh_update_bmesh_offsets(ss->pbvh, + ob->sculpt->attrs.dyntopo_node_id_vertex->bmesh_cd_offset, + ob->sculpt->attrs.dyntopo_node_id_face->bmesh_cd_offset); + } +} + +void sculptsession_bmesh_add_layers(Object *ob) +{ + SculptSession *ss = ob->sculpt; + SculptAttributeParams params = {0}; + + ss->attrs.dyntopo_node_id_vertex = sculpt_attribute_ensure_ex( + ob, + ATTR_DOMAIN_POINT, + CD_PROP_INT32, + SCULPT_ATTRIBUTE_NAME(dyntopo_node_id_vertex), + ¶ms, + PBVH_BMESH, + false); + + ss->attrs.dyntopo_node_id_face = sculpt_attribute_ensure_ex( + ob, + ATTR_DOMAIN_FACE, + CD_PROP_INT32, + SCULPT_ATTRIBUTE_NAME(dyntopo_node_id_face), + ¶ms, + PBVH_BMESH, + false); +} + +void BKE_sculpt_attributes_destroy_temporary_stroke(Object *ob) +{ + SculptSession *ss = ob->sculpt; + + for (int i = 0; i < SCULPT_MAX_ATTRIBUTES; i++) { + SculptAttribute *attr = ss->temp_attributes + i; + + if (attr->params.stroke_only) { + BKE_sculpt_attribute_destroy(ob, attr); + } + } +} + +static void sculpt_attribute_update_refs(Object *ob) +{ + SculptSession *ss = ob->sculpt; + + /* run twice, in case sculpt_attr_update had to recreate a layer and + messed up the bmesh offsets. */ + for (int i = 0; i < 2; i++) { + for (int j = 0; j < SCULPT_MAX_ATTRIBUTES; j++) { + SculptAttribute *attr = ss->temp_attributes + j; + + if (attr->used) { + sculpt_attr_update(ob, attr); + } + } + + if (ss->bm) { + sculptsession_bmesh_attr_update_internal(ob); + } + } + + Mesh *me = BKE_object_get_original_mesh(ob); + + if (ss->pbvh) { + BKE_pbvh_update_active_vcol(ss->pbvh, me); + } +} + +bool BKE_paint_uses_channels(ePaintMode mode) +{ + return mode == PAINT_MODE_SCULPT; +} + +void BKE_sculpt_attribute_destroy_temporary_all(Object *ob) +{ + SculptSession *ss = ob->sculpt; + + for (int i = 0; i < SCULPT_MAX_ATTRIBUTES; i++) { + SculptAttribute *attr = ss->temp_attributes + i; + + if (attr->used && !attr->params.permanent) { + BKE_sculpt_attribute_destroy(ob, attr); + } + } +} + +bool BKE_sculpt_attribute_destroy(Object *ob, SculptAttribute *attr) +{ + SculptSession *ss = ob->sculpt; + eAttrDomain domain = attr->domain; + + BLI_assert(attr->used); + + /* Remove from convienience pointer struct. */ + SculptAttribute **ptrs = (SculptAttribute **)&ss->attrs; + int ptrs_num = sizeof(ss->attrs) / sizeof(void *); + + for (int i = 0; i < ptrs_num; i++) { + if (ptrs[i] == attr) { + ptrs[i] = NULL; + } + } + + /* Remove from internal temp_attributes array. */ + for (int i = 0; i < SCULPT_MAX_ATTRIBUTES; i++) { + SculptAttribute *attr2 = ss->temp_attributes + i; + + if (STREQ(attr2->name, attr->name) && attr2->domain == attr->domain && + attr2->proptype == attr->proptype) { + + attr2->used = false; + } + } + + Mesh *me = BKE_object_get_original_mesh(ob); + + if (attr->params.simple_array) { + MEM_SAFE_FREE(attr->data); + } + else if (ss->bm) { + CustomData *cdata = attr->domain == ATTR_DOMAIN_POINT ? &ss->bm->vdata : &ss->bm->pdata; + + BM_data_layer_free_named(ss->bm, cdata, attr->name); + } + else { + CustomData *cdata = NULL; + int totelem = 0; + + switch (domain) { + case ATTR_DOMAIN_POINT: + cdata = ss->bm ? &ss->bm->vdata : &me->vdata; + totelem = ss->totvert; + break; + case ATTR_DOMAIN_FACE: + cdata = ss->bm ? &ss->bm->pdata : &me->pdata; + totelem = ss->totfaces; + break; + default: + BLI_assert_unreachable(); + return false; + } + + /* We may have been called after destroying ss->bm in which case attr->layer + * might be invalid. + */ + int layer_i = CustomData_get_named_layer_index(cdata, attr->proptype, attr->name); + if (layer_i != 0) { + CustomData_free_layer(cdata, attr->proptype, totelem, layer_i); + } + + sculpt_attribute_update_refs(ob); + } + + attr->data = NULL; + attr->used = false; + + return true; +} diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index b3de2b17dd8..2bed18de6cf 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -631,11 +631,12 @@ void BKE_pbvh_build_grids(PBVH *pbvh, MEM_freeN(prim_bbc); } -PBVH *BKE_pbvh_new(void) +PBVH *BKE_pbvh_new(PBVHType type) { PBVH *pbvh = MEM_callocN(sizeof(PBVH), "pbvh"); pbvh->respect_hide = true; pbvh->draw_cache_invalid = true; + pbvh->header.type = type; return pbvh; } diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c index c4993684100..e065180b600 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.c +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -1863,6 +1863,12 @@ static void pbvh_bmesh_create_nodes_fast_recursive( /***************************** Public API *****************************/ +void BKE_pbvh_update_bmesh_offsets(PBVH *pbvh, int cd_vert_node_offset, int cd_face_node_offset) +{ + pbvh->cd_vert_node_offset = cd_vert_node_offset; + pbvh->cd_face_node_offset = cd_face_node_offset; +} + void BKE_pbvh_build_bmesh(PBVH *pbvh, BMesh *bm, bool smooth_shading, @@ -1870,8 +1876,6 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh, const int cd_vert_node_offset, const int cd_face_node_offset) { - pbvh->cd_vert_node_offset = cd_vert_node_offset; - pbvh->cd_face_node_offset = cd_face_node_offset; pbvh->header.bm = bm; BKE_pbvh_bmesh_detail_size_set(pbvh, 0.75); @@ -1882,6 +1886,8 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh, /* TODO: choose leaf limit better */ pbvh->leaf_limit = 100; + BKE_pbvh_update_bmesh_offsets(pbvh, cd_vert_node_offset, cd_face_node_offset); + if (smooth_shading) { pbvh->flags |= PBVH_DYNTOPO_SMOOTH_SHADING; } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 1cb466db304..53f65960ede 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -194,9 +194,10 @@ void SCULPT_vertex_normal_get(SculptSession *ss, PBVHVertRef vertex, float no[3] const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, PBVHVertRef vertex) { - if (ss->persistent_base) { - return ss->persistent_base[BKE_pbvh_vertex_to_index(ss->pbvh, vertex)].co; + if (ss->attrs.persistent_co) { + return (const float *)SCULPT_vertex_attr_get(vertex, ss->attrs.persistent_co); } + return SCULPT_vertex_co_get(ss, vertex); } @@ -240,8 +241,8 @@ void SCULPT_vertex_limit_surface_get(SculptSession *ss, PBVHVertRef vertex, floa void SCULPT_vertex_persistent_normal_get(SculptSession *ss, PBVHVertRef vertex, float no[3]) { - if (ss->persistent_base) { - copy_v3_v3(no, ss->persistent_base[vertex.i].no); + if (ss->attrs.persistent_no) { + copy_v3_v3(no, (float *)SCULPT_vertex_attr_get(vertex, ss->attrs.persistent_no)); return; } SCULPT_vertex_normal_get(ss, vertex, no); @@ -5322,6 +5323,8 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateColor); } + BKE_sculpt_attributes_destroy_temporary_stroke(ob); + if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) { BKE_pbvh_bmesh_after_stroke(ss->pbvh); } diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.cc b/source/blender/editors/sculpt_paint/sculpt_automasking.cc index a9fe8cc4b2f..34d7a459c1b 100644 --- a/source/blender/editors/sculpt_paint/sculpt_automasking.cc +++ b/source/blender/editors/sculpt_paint/sculpt_automasking.cc @@ -122,13 +122,11 @@ float SCULPT_automasking_factor_get(AutomaskingCache *automasking, return 1.0f; } - int index = BKE_pbvh_vertex_to_index(ss->pbvh, vert); - /* If the cache is initialized with valid info, use the cache. This is used when the * automasking information can't be computed in real time per vertex and needs to be * initialized for the whole mesh when the stroke starts. */ - if (automasking->factor) { - return automasking->factor[index]; + if (ss->attrs.automasking_factor) { + return *(float *)SCULPT_vertex_attr_get(vert, ss->attrs.automasking_factor); } if (automasking->settings.flags & BRUSH_AUTOMASKING_FACE_SETS) { @@ -158,7 +156,6 @@ void SCULPT_automasking_cache_free(AutomaskingCache *automasking) return; } - MEM_SAFE_FREE(automasking->factor); MEM_SAFE_FREE(automasking); } @@ -176,7 +173,6 @@ static bool sculpt_automasking_is_constrained_by_radius(Brush *br) } struct AutomaskFloodFillData { - float *automask_factor; float radius; bool use_radius; float location[3]; @@ -190,29 +186,29 @@ static bool automask_floodfill_cb(SculptSession *ss, void *userdata) { AutomaskFloodFillData *data = (AutomaskFloodFillData *)userdata; - int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v); - int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); - data->automask_factor[to_v_i] = 1.0f; - data->automask_factor[from_v_i] = 1.0f; + *(float *)SCULPT_vertex_attr_get(to_v, ss->attrs.automasking_factor) = 1.0f; + *(float *)SCULPT_vertex_attr_get(from_v, ss->attrs.automasking_factor) = 1.0f; return (!data->use_radius || SCULPT_is_vertex_inside_brush_radius_symm( SCULPT_vertex_co_get(ss, to_v), data->location, data->radius, data->symm)); } -static float *SCULPT_topology_automasking_init(Sculpt *sd, Object *ob, float *automask_factor) +static void SCULPT_topology_automasking_init(Sculpt *sd, Object *ob) { SculptSession *ss = ob->sculpt; Brush *brush = BKE_paint_brush(&sd->paint); if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) { BLI_assert_msg(0, "Topology masking: pmap missing"); - return nullptr; + return; } const int totvert = SCULPT_vertex_count_get(ss); for (int i : IndexRange(totvert)) { - automask_factor[i] = 0.0f; + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + (*(float *)SCULPT_vertex_attr_get(vertex, ss->attrs.automasking_factor)) = 0.0f; } /* Flood fill automask to connected vertices. Limited to vertices inside @@ -222,9 +218,8 @@ static float *SCULPT_topology_automasking_init(Sculpt *sd, Object *ob, float *au const float radius = ss->cache ? ss->cache->radius : FLT_MAX; SCULPT_floodfill_add_active(sd, ob, ss, &flood, radius); - AutomaskFloodFillData fdata = {nullptr}; + AutomaskFloodFillData fdata = {0}; - fdata.automask_factor = automask_factor; fdata.radius = radius; fdata.use_radius = ss->cache && sculpt_automasking_is_constrained_by_radius(brush); fdata.symm = SCULPT_mesh_symmetry_xyz_get(ob); @@ -232,22 +227,20 @@ static float *SCULPT_topology_automasking_init(Sculpt *sd, Object *ob, float *au copy_v3_v3(fdata.location, SCULPT_active_vertex_co_get(ss)); SCULPT_floodfill_execute(ss, &flood, automask_floodfill_cb, &fdata); SCULPT_floodfill_free(&flood); - - return automask_factor; } -static float *sculpt_face_sets_automasking_init(Sculpt *sd, Object *ob, float *automask_factor) +static void sculpt_face_sets_automasking_init(Sculpt *sd, Object *ob) { SculptSession *ss = ob->sculpt; Brush *brush = BKE_paint_brush(&sd->paint); if (!SCULPT_is_automasking_enabled(sd, ss, brush)) { - return nullptr; + return; } if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) { BLI_assert_msg(0, "Face Sets automasking: pmap missing"); - return nullptr; + return; } int tot_vert = SCULPT_vertex_count_get(ss); @@ -256,25 +249,22 @@ static float *sculpt_face_sets_automasking_init(Sculpt *sd, Object *ob, float *a PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); if (!SCULPT_vertex_has_face_set(ss, vertex, active_face_set)) { - automask_factor[i] *= 0.0f; + *(float *)SCULPT_vertex_attr_get(vertex, ss->attrs.automasking_factor) = 0.0f; } } - - return automask_factor; } #define EDGE_DISTANCE_INF -1 -float *SCULPT_boundary_automasking_init(Object *ob, - eBoundaryAutomaskMode mode, - int propagation_steps, - float *automask_factor) +void SCULPT_boundary_automasking_init(Object *ob, + eBoundaryAutomaskMode mode, + int propagation_steps) { SculptSession *ss = ob->sculpt; if (!ss->pmap) { BLI_assert_msg(0, "Boundary Edges masking: pmap missing"); - return nullptr; + return; } const int totvert = SCULPT_vertex_count_get(ss); @@ -316,16 +306,19 @@ float *SCULPT_boundary_automasking_init(Object *ob, } for (int i : IndexRange(totvert)) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + if (edge_distance[i] == EDGE_DISTANCE_INF) { continue; } const float p = 1.0f - ((float)edge_distance[i] / (float)propagation_steps); const float edge_boundary_automask = pow2f(p); - automask_factor[i] *= (1.0f - edge_boundary_automask); + + *(float *)SCULPT_vertex_attr_get( + vertex, ss->attrs.automasking_factor) *= (1.0f - edge_boundary_automask); } MEM_SAFE_FREE(edge_distance); - return automask_factor; } static void SCULPT_automasking_cache_settings_update(AutomaskingCache *automasking, @@ -355,9 +348,16 @@ AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object return automasking; } - automasking->factor = (float *)MEM_malloc_arrayN(totvert, sizeof(float), "automask_factor"); + SculptAttributeParams params = {0}; + params.stroke_only = true; + + ss->attrs.automasking_factor = BKE_sculpt_attribute_ensure( + ob, ATTR_DOMAIN_POINT, CD_PROP_FLOAT, SCULPT_ATTRIBUTE_NAME(automasking_factor), ¶ms); + for (int i : IndexRange(totvert)) { - automasking->factor[i] = 1.0f; + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + (*(float *)SCULPT_vertex_attr_get(vertex, ss->attrs.automasking_factor)) = 0.0f; } const int boundary_propagation_steps = brush ? @@ -366,22 +366,21 @@ AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_TOPOLOGY)) { SCULPT_vertex_random_access_ensure(ss); - SCULPT_topology_automasking_init(sd, ob, automasking->factor); + SCULPT_topology_automasking_init(sd, ob); } if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_FACE_SETS)) { SCULPT_vertex_random_access_ensure(ss); - sculpt_face_sets_automasking_init(sd, ob, automasking->factor); + sculpt_face_sets_automasking_init(sd, ob); } if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_BOUNDARY_EDGES)) { SCULPT_vertex_random_access_ensure(ss); - SCULPT_boundary_automasking_init( - ob, AUTOMASK_INIT_BOUNDARY_EDGES, boundary_propagation_steps, automasking->factor); + SCULPT_boundary_automasking_init(ob, AUTOMASK_INIT_BOUNDARY_EDGES, boundary_propagation_steps); } if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS)) { SCULPT_vertex_random_access_ensure(ss); SCULPT_boundary_automasking_init( - ob, AUTOMASK_INIT_BOUNDARY_FACE_SETS, boundary_propagation_steps, automasking->factor); + ob, AUTOMASK_INIT_BOUNDARY_FACE_SETS, boundary_propagation_steps); } return automasking; diff --git a/source/blender/editors/sculpt_paint/sculpt_brush_types.c b/source/blender/editors/sculpt_paint/sculpt_brush_types.c index 245cbe0f54e..e849cc9e5f4 100644 --- a/source/blender/editors/sculpt_paint/sculpt_brush_types.c +++ b/source/blender/editors/sculpt_paint/sculpt_brush_types.c @@ -1472,7 +1472,7 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata, Sculpt *sd = data->sd; const Brush *brush = data->brush; - const bool use_persistent_base = ss->persistent_base && brush->flag & BRUSH_PERSISTENT; + const bool use_persistent_base = !ss->bm && ss->attrs.persistent_co && brush->flag & BRUSH_PERSISTENT; PBVHVertexIter vd; SculptOrigVertData orig_data; @@ -1503,7 +1503,7 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata, const int vi = vd.index; float *disp_factor; if (use_persistent_base) { - disp_factor = &ss->persistent_base[vi].disp; + disp_factor = (float *)SCULPT_vertex_attr_get(vd.vertex, ss->attrs.persistent_disp); } else { disp_factor = &ss->cache->layer_displacement_factor[vi]; diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c index 46674c5d239..1126d34bcee 100644 --- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c +++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c @@ -88,45 +88,6 @@ void SCULPT_pbvh_clear(Object *ob) DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); } -void SCULPT_dyntopo_node_layers_add(SculptSession *ss) -{ - int cd_node_layer_index; - - char node_vertex_id[] = "_dyntopo_vnode_id"; - char node_face_id[] = "_dyntopo_fnode_id"; - - cd_node_layer_index = CustomData_get_named_layer_index( - &ss->bm->vdata, CD_PROP_INT32, node_vertex_id); - - if (cd_node_layer_index == -1) { - BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_INT32, node_vertex_id); - cd_node_layer_index = CustomData_get_named_layer_index( - &ss->bm->vdata, CD_PROP_INT32, node_vertex_id); - } - - ss->cd_vert_node_offset = CustomData_get_n_offset( - &ss->bm->vdata, - CD_PROP_INT32, - cd_node_layer_index - CustomData_get_layer_index(&ss->bm->vdata, CD_PROP_INT32)); - - ss->bm->vdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY; - - cd_node_layer_index = CustomData_get_named_layer_index( - &ss->bm->pdata, CD_PROP_INT32, node_face_id); - if (cd_node_layer_index == -1) { - BM_data_layer_add_named(ss->bm, &ss->bm->pdata, CD_PROP_INT32, node_face_id); - cd_node_layer_index = CustomData_get_named_layer_index( - &ss->bm->pdata, CD_PROP_INT32, node_face_id); - } - - ss->cd_face_node_offset = CustomData_get_n_offset( - &ss->bm->pdata, - CD_PROP_INT32, - cd_node_layer_index - CustomData_get_layer_index(&ss->bm->pdata, CD_PROP_INT32)); - - ss->bm->pdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY; -} - void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob) { SculptSession *ss = ob->sculpt; @@ -156,8 +117,9 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene .active_shapekey = ob->shapenr, })); SCULPT_dynamic_topology_triangulate(ss->bm); + BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK); - SCULPT_dyntopo_node_layers_add(ss); + /* Make sure the data for existing faces are initialized. */ if (me->totpoly != ss->bm->totface) { BM_mesh_normals_update(ss->bm); @@ -185,6 +147,9 @@ static void SCULPT_dynamic_topology_disable_ex( SculptSession *ss = ob->sculpt; Mesh *me = ob->data; + BKE_sculpt_attribute_destroy(ob, ss->attrs.dyntopo_node_id_vertex); + BKE_sculpt_attribute_destroy(ob, ss->attrs.dyntopo_node_id_face); + SCULPT_pbvh_clear(ob); if (unode) { diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 681c90bafb6..cdfa9c2586f 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -402,9 +402,6 @@ typedef struct AutomaskingSettings { typedef struct AutomaskingCache { AutomaskingSettings settings; - /* Precomputed auto-mask factor indexed by vertex, owned by the auto-masking system and - * initialized in #SCULPT_automasking_cache_init when needed. */ - float *factor; } AutomaskingCache; typedef struct FilterCache { @@ -1273,7 +1270,6 @@ void sculpt_dynamic_topology_disable_with_undo(struct Main *bmain, bool SCULPT_stroke_is_dynamic_topology(const SculptSession *ss, const Brush *brush); void SCULPT_dynamic_topology_triangulate(struct BMesh *bm); -void SCULPT_dyntopo_node_layers_add(struct SculptSession *ss); enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob); @@ -1849,3 +1845,8 @@ BLI_INLINE bool SCULPT_tool_is_face_sets(int tool) #ifdef __cplusplus } #endif + +/* Make SCULPT_ alias to a few blenkernel sculpt methods. */ + +#define SCULPT_vertex_attr_get BKE_sculpt_vertex_attr_get +#define SCULPT_face_attr_get BKE_sculpt_face_attr_get diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c index cfd02438188..39c77129f0e 100644 --- a/source/blender/editors/sculpt_paint/sculpt_ops.c +++ b/source/blender/editors/sculpt_paint/sculpt_ops.c @@ -117,24 +117,33 @@ static int sculpt_set_persistent_base_exec(bContext *C, wmOperator *UNUSED(op)) Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; - if (!ss) { + /* Do not allow in DynTopo just yet. */ + if (!ss || (ss && ss->bm)) { return OPERATOR_FINISHED; } SCULPT_vertex_random_access_ensure(ss); BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false); - MEM_SAFE_FREE(ss->persistent_base); + SculptAttributeParams params = {0}; + params.permanent = true; + + ss->attrs.persistent_co = BKE_sculpt_attribute_ensure( + ob, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, SCULPT_ATTRIBUTE_NAME(persistent_co), ¶ms); + ss->attrs.persistent_no = BKE_sculpt_attribute_ensure( + ob, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, SCULPT_ATTRIBUTE_NAME(persistent_no), ¶ms); + ss->attrs.persistent_disp = BKE_sculpt_attribute_ensure( + ob, ATTR_DOMAIN_POINT, CD_PROP_FLOAT, SCULPT_ATTRIBUTE_NAME(persistent_disp), ¶ms); const int totvert = SCULPT_vertex_count_get(ss); - ss->persistent_base = MEM_mallocN(sizeof(SculptPersistentBase) * totvert, - "layer persistent base"); for (int i = 0; i < totvert; i++) { PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); - copy_v3_v3(ss->persistent_base[i].co, SCULPT_vertex_co_get(ss, vertex)); - SCULPT_vertex_normal_get(ss, vertex, ss->persistent_base[i].no); - ss->persistent_base[i].disp = 0.0f; + copy_v3_v3((float *)SCULPT_vertex_attr_get(vertex, ss->attrs.persistent_co), + SCULPT_vertex_co_get(ss, vertex)); + SCULPT_vertex_normal_get( + ss, vertex, (float *)SCULPT_vertex_attr_get(vertex, ss->attrs.persistent_no)); + (*(float *)SCULPT_vertex_attr_get(vertex, ss->attrs.persistent_disp)) = 0.0f; } return OPERATOR_FINISHED; diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 9bf63ad1468..d37bf9b052d 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -547,7 +547,7 @@ static void sculpt_undo_bmesh_enable(Object *ob, SculptUndoNode *unode) .use_toolflags = false, })); BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK); - SCULPT_dyntopo_node_layers_add(ss); + me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY; /* Restore the BMLog using saved entries. */ |