Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/BKE_customdata.h2
-rw-r--r--source/blender/blenkernel/BKE_paint.h164
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h4
-rw-r--r--source/blender/blenkernel/intern/customdata.cc5
-rw-r--r--source/blender/blenkernel/intern/paint.cc607
-rw-r--r--source/blender/blenkernel/intern/pbvh.c3
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c10
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c11
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_automasking.cc73
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_brush_types.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_dyntopo.c45
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h9
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_ops.c23
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c2
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),
+ &params,
+ 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),
+ &params,
+ 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), &params);
+
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), &params);
+ ss->attrs.persistent_no = BKE_sculpt_attribute_ensure(
+ ob, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, SCULPT_ATTRIBUTE_NAME(persistent_no), &params);
+ ss->attrs.persistent_disp = BKE_sculpt_attribute_ensure(
+ ob, ATTR_DOMAIN_POINT, CD_PROP_FLOAT, SCULPT_ATTRIBUTE_NAME(persistent_disp), &params);
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. */