[Bf-blender-cvs] [02575bcbd0a] master: Sculpt: New attribute API

Joseph Eagar noreply at git.blender.org
Fri Sep 16 21:27:00 CEST 2022


Commit: 02575bcbd0a91f499f13d15860adc3896920b9ff
Author: Joseph Eagar
Date:   Fri Sep 16 12:20:28 2022 -0700
Branches: master
https://developer.blender.org/rB02575bcbd0a91f499f13d15860adc3896920b9ff

Sculpt: New attribute API

New unified attribute API for sculpt code.

= Basic Design =

The sculpt attribute API can create temporary or permanent attributes (only supported in `PBVH_FACES` mode).  Attributes are created via `BKE_sculpt_attribute_ensure.`

Attributes can be explicit CustomData attributes or simple array-based pseudo-attributes (this is useful for PBVH_GRIDS and PBVH_BMESH).

== `SculptAttributePointers` ==

There is a structure in `SculptSession` for convenience attribute pointers, `ss->attrs`.  Standard attributes should assign these; the attribute API will automatically clear them when the associated attributes are released.  For example, the automasking code stores its factor attribute layer in `ss->attrs.automasking_factor`.

== Naming ==

Temporary attributes should use the SCULPT_ATTRIBUTE_NAME macro for naming, it takes an entry in `SculptAttributePointers` and builds a layer name.

== `SculptAttribute` ==

Attributes are referenced by a special `SculptAttribute` structure, which holds
all the info needed to look up elements of an attribute at run time.

All of these structures live in a preallocated flat array in `SculptSession`, `ss->temp_attributes`.  This is extremely important.  Since any change to the `CustomData` layout can in principle invalidate every extant `SculptAttribute`, having them all in one block of memory whose location doesn't change allows us to update them transparently.

This makes for much simpler code and eliminates bugs.  To see why this is tricky to get right, imagine we want to create three attributes in PBVH_BMESH mode and we provide our own `SculptAttribute` structs for the API to fill in.  Each new layer will invalidate the `CustomData` block offsets in the prior one, leading to memory corruption.

Reviewed by: Brecht Van Lommel
Differential Revision: https://developer.blender.org/D15496
Ref D15496

===================================================================

M	source/blender/blenkernel/BKE_customdata.h
M	source/blender/blenkernel/BKE_paint.h
M	source/blender/blenkernel/BKE_pbvh.h
M	source/blender/blenkernel/intern/customdata.cc
M	source/blender/blenkernel/intern/paint.cc
M	source/blender/blenkernel/intern/pbvh.c
M	source/blender/blenkernel/intern/pbvh_bmesh.c
M	source/blender/editors/sculpt_paint/sculpt.c
M	source/blender/editors/sculpt_paint/sculpt_automasking.cc
M	source/blender/editors/sculpt_paint/sculpt_brush_types.c
M	source/blender/editors/sculpt_paint/sculpt_dyntopo.c
M	source/blender/editors/sculpt_paint/sculpt_intern.h
M	source/blender/editors/sculpt_paint/sculpt_ops.c
M	source/blender/editors/sculpt_paint/sculpt_undo.c

===================================================================

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 @@ eCustomDataTyp

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list