[Bf-blender-cvs] [bb97284f8aa] geometry-nodes: Geometry Nodes: refactor Geometry type

Jacques Lucke noreply at git.blender.org
Thu Oct 29 15:38:23 CET 2020


Commit: bb97284f8aa63a87c682b0b3f98c9aff3700a174
Author: Jacques Lucke
Date:   Thu Oct 29 15:38:15 2020 +0100
Branches: geometry-nodes
https://developer.blender.org/rBbb97284f8aa63a87c682b0b3f98c9aff3700a174

Geometry Nodes: refactor Geometry type

A geometry now contains zero or more geometry components.
A geometry component is a subclass off GeometryComponent.
Currently, there is a MeshComponent and PointCloudComponent.

A geometry contains at most one component of each type.
Individual components can be shared between multiple geometries
to avoid unnecessary copies. For that, each component has a user
count that determines when the component will be freed and whether
it is mutable.

Code working with geometries can either work with the components
directly, or use the utility functions on the geometry that cover the
most common operations.

In the future, additional component types can be added. For example,
we'll probably need components for curves and volumes.
Furthermore, something like an InstancesComponent can be added,
which contains points with attributes and references a geometry/object/collection
that is instanced on all the points.

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

M	source/blender/blenkernel/BKE_geometry.hh
M	source/blender/blenkernel/intern/geometry.cc
A	source/blender/blenlib/BLI_user_counter.hh
M	source/blender/blenlib/CMakeLists.txt
M	source/blender/modifiers/intern/MOD_edgesplit.c
M	source/blender/modifiers/intern/MOD_nodes.cc
M	source/blender/nodes/NOD_geometry_exec.hh
M	source/blender/nodes/geometry/nodes/node_geo_boolean.cc
M	source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
M	source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
M	source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
M	source/blender/nodes/geometry/nodes/node_geo_transform.cc
M	source/blender/nodes/geometry/nodes/node_geo_triangulate.cc

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

diff --git a/source/blender/blenkernel/BKE_geometry.hh b/source/blender/blenkernel/BKE_geometry.hh
index 1ad34a8a3fb..fd03b110749 100644
--- a/source/blender/blenkernel/BKE_geometry.hh
+++ b/source/blender/blenkernel/BKE_geometry.hh
@@ -24,15 +24,66 @@
 #include <iostream>
 
 #include "BLI_hash.hh"
+#include "BLI_map.hh"
+#include "BLI_user_counter.hh"
 
 struct Mesh;
 struct PointCloud;
 
 namespace blender::bke {
 
+/* An automatically reference counted geometry. */
+using GeometryPtr = UserCounter<class Geometry>;
+
+/* Each geometry component has a specific type. The type determines what kind of data the component
+ * stores. Functions modifying a geometry will usually just modify a subset of the component types.
+ */
+enum class GeometryComponentType {
+  Mesh,
+  PointCloud,
+};
+
+}  // namespace blender::bke
+
+/* Make it possible to use the component type as key in hash tables. */
+namespace blender {
+template<> struct DefaultHash<bke::GeometryComponentType> {
+  uint64_t operator()(const bke::GeometryComponentType &value) const
+  {
+    return (uint64_t)value;
+  }
+};
+}  // namespace blender
+
+namespace blender::bke {
+
+/**
+ * This is the base class for specialized geometry component types.
+ */
+class GeometryComponent {
+ private:
+  /* The reference count has two purposes. When it becomes zero, the component is freed. When it is
+   * larger than one, the component becomes immutable. */
+  std::atomic<int> users_ = 1;
+
+ public:
+  virtual ~GeometryComponent();
+  static GeometryComponent *create(GeometryComponentType component_type);
+
+  /* The returned component should be of the same type as the type this is called on. */
+  virtual GeometryComponent *copy() const = 0;
+
+  void user_add();
+  void user_remove();
+  bool is_mutable() const;
+};
+
+template<typename T>
+inline constexpr bool is_geometry_component_v = std::is_base_of_v<GeometryComponent, T>;
+
 /**
- * Geometry can contain geometry of different types, such as meshes and curves (although currently
- * only meshes are supported).
+ * A geometry contains zero or more geometry components. There is at most one component of each
+ * type. Individual components might be shared between multiple geometries.
  *
  * Geometries are reference counted. This allows them to be shared without making unnecessary
  * copies. A geometry that is shared is immutable. If some code wants to change it,
@@ -40,23 +91,18 @@ namespace blender::bke {
  */
 class Geometry {
  private:
-  /* Number of users of this geometry. If this number goes to zero, the geometry is freed. If it is
-   * above 1, the geometry is immutable. */
+  /* Number of users of this geometry. If this number goes to zero, the geometry is freed. If it
+   * is above 1, the geometry is immutable. */
   std::atomic<int> users_ = 1;
 
-  Mesh *mesh_ = nullptr;
-  /* Determines if the mesh is freed when the geometry does not want to reference it anymore. */
-  bool mesh_owned_ = false;
-
-  PointCloud *pointcloud_ = nullptr;
-  /* True if the pointcloud is freed with the geometry. */
-  bool pointcloud_owned_ = false;
+  using GeometryComponentPtr = UserCounter<class GeometryComponent>;
+  Map<GeometryComponentType, GeometryComponentPtr> components_;
 
  public:
   Geometry() = default;
   Geometry(const Geometry &other);
   Geometry(Geometry &&other) = delete;
-  ~Geometry();
+  ~Geometry() = default;
 
   /* Disable copy and move assignment operators. */
   Geometry &operator=(const Geometry &other) = delete;
@@ -66,152 +112,78 @@ class Geometry {
   void user_remove();
   bool is_mutable() const;
 
-  bool mesh_available() const;
-  void mesh_set_and_keep_ownership(Mesh *mesh);
-  void mesh_set_and_transfer_ownership(Mesh *mesh);
-  void mesh_reset();
-  Mesh *mesh_get_for_read();
-  Mesh *mesh_get_for_write();
-  Mesh *mesh_release();
-
-  bool pointcloud_available() const;
-  void pointcloud_set_and_keep_ownership(PointCloud *pointcloud);
-  void pointcloud_set_and_transfer_ownership(PointCloud *pointcloud);
-  void pointcloud_reset();
-  PointCloud *pointcloud_get_for_read();
-  PointCloud *pointcloud_get_for_write();
-  PointCloud *pointcloud_release();
-};
-
-/**
- * A simple automatic reference counter. This should probably be moved to another file eventually.
- * It is similar to std::shared_ptr, but expects that the reference count is inside the object.
- */
-template<typename T> class UserCounter {
- private:
-  T *data_ = nullptr;
-
- public:
-  UserCounter() = default;
-
-  UserCounter(T *data) : data_(data)
-  {
-  }
-
-  UserCounter(const UserCounter &other) : data_(other.data_)
-  {
-    this->user_add(data_);
-  }
-
-  UserCounter(UserCounter &&other) : data_(other.data_)
+  GeometryComponent &get_component_for_write(GeometryComponentType component_type);
+  template<typename Component> Component &get_component_for_write()
   {
-    other.data_ = nullptr;
+    BLI_STATIC_ASSERT(is_geometry_component_v<Component>, "");
+    return static_cast<Component &>(this->get_component_for_write(Component::type));
   }
 
-  ~UserCounter()
+  const GeometryComponent *get_component_for_read(GeometryComponentType component_type) const;
+  template<typename Component> const Component *get_component_for_read() const
   {
-    this->user_remove(data_);
+    BLI_STATIC_ASSERT(is_geometry_component_v<Component>, "");
+    return static_cast<const Component *>(get_component_for_read(Component::type));
   }
 
-  UserCounter &operator=(const UserCounter &other)
-  {
-    if (this == &other) {
-      return *this;
-    }
-
-    this->user_remove(data_);
-    data_ = other.data_;
-    this->user_add(data_);
-    return *this;
-  }
+  /* Utility methods for creation. */
+  static GeometryPtr create_with_mesh(Mesh *mesh, bool transfer_ownership = true);
 
-  UserCounter &operator=(UserCounter &&other)
-  {
-    if (this == &other) {
-      return *this;
-    }
-
-    this->user_remove(data_);
-    data_ = other.data_;
-    other.data_ = nullptr;
-    return *this;
-  }
+  /* Utility methods for access. */
+  bool has_mesh() const;
+  bool has_pointcloud() const;
+  const Mesh *get_mesh_for_read() const;
+  const PointCloud *get_pointcloud_for_read() const;
+  Mesh *get_mesh_for_write();
+  PointCloud *get_pointcloud_for_write();
 
-  T *operator->()
-  {
-    BLI_assert(data_ != nullptr);
-    return data_;
-  }
+  /* Utility methods for replacement. */
+  void replace_mesh(Mesh *mesh, bool transfer_ownership = true);
+  void replace_pointcloud(PointCloud *pointcloud, bool transfer_ownership = true);
+};
 
-  T &operator*()
-  {
-    BLI_assert(data_ != nullptr);
-    return *data_;
-  }
+void make_geometry_mutable(GeometryPtr &geometry);
 
-  operator bool() const
-  {
-    return data_ != nullptr;
-  }
+/** A geometry component that can store a mesh. */
+class MeshComponent : public GeometryComponent {
+ private:
+  Mesh *mesh_ = nullptr;
+  bool owned_ = false;
 
-  T *get()
-  {
-    return data_;
-  }
+ public:
+  ~MeshComponent();
+  GeometryComponent *copy() const override;
 
-  T *release()
-  {
-    T *data = data_;
-    data_ = nullptr;
-    return data;
-  }
+  void clear();
+  bool has_mesh() const;
+  void replace(Mesh *mesh, bool transfer_ownership = true);
+  Mesh *release();
 
-  void reset()
-  {
-    this->user_remove(data_);
-    data_ = nullptr;
-  }
+  const Mesh *get_for_read() const;
+  Mesh *get_for_write();
 
-  bool has_value() const
-  {
-    return data_ != nullptr;
-  }
+  static constexpr inline GeometryComponentType type = GeometryComponentType::Mesh;
+};
 
-  uint64_t hash() const
-  {
-    return DefaultHash<T *>{}(data_);
-  }
+/** A geometry component that stores a point cloud. */
+class PointCloudComponent : public GeometryComponent {
+ private:
+  PointCloud *pointcloud_ = nullptr;
+  bool owned_ = false;
 
-  friend bool operator==(const UserCounter &a, const UserCounter &b)
-  {
-    return a.data_ == b.data_;
-  }
+ public:
+  ~PointCloudComponent();
+  GeometryComponent *copy() const override;
 
-  friend std::ostream &operator<<(std::ostream &stream, const UserCounter &value)
-  {
-    stream << value.data_;
-    return stream;
-  }
+  void clear();
+  bool has_pointcloud() const;
+  void replace(PointCloud *pointcloud, bool transfer_ownership = true);
+  PointCloud *release();
 
- private:
-  static void user_add(T *data)
-  {
-    if (data != nullptr) {
-      data->user_add();
-    }
-  }
+  const PointCloud *get_for_read() const;
+  PointCloud *get_for_write();
 
-  static void user_remove(T *data)
-  {
-    if (data != nullptr) {
-      data->user_remove();
-    }
-  }
+  static constexpr inline GeometryComponentType type = GeometryComponentType::PointCloud;
 };
 
-/* An automatically reference counted geometry. */
-using GeometryPtr = UserCounter<class Geometry>;
-
-void make_geometry_mutable(GeometryPtr &geometry);
-
 }  // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/geometry.cc b/source/blender/blenkernel/intern/geometry.cc
index 2282b544b78..2ca5fa74261 100644
--- a/source/blender/blenkernel/intern/geometry.cc
+++ b/source/blender/blenkernel/intern/geometry.cc
@@ -23,25 +23,57 @@
 
 namespace blender::bke {
 
-/* Make a copy of the geometry. */
-Geometry::Geometry(const Geometry &other)
+/* -------------------------------------------------------------------- */
+/** \name Geometry Component
+ * \{ */
+
+GeometryComponent ::~GeometryComponent()
+{
+}
+
+GeometryComponent *GeometryComponent::create(GeometryComponentType component_type)
 {
-  if (other.mesh_ != nullptr) {
-    mesh_ = BKE_mesh_copy_for_eval(other.mesh_, false);
-    /* Own the new mesh, regardless of whether the original mesh was owned. */
-    mesh_owned_ = true;
+  switch (component_type) {
+    case GeometryComponentType::Mesh:
+      return new MeshComponent();
+    case GeometryComponentType::PointCloud:
+      return new PointCloudComponent();
   }
-  if (other.pointcloud_ != nullptr) {
-    pointcloud_ = BKE_pointcloud_copy_for_eval(other.pointcloud_, false);
-    /* Own the new pointcloud, regardless of whether the original mesh was owned. */
-    pointcloud_owned_ = true;
+  BLI_assert(false);
+  return nullptr;
+}
+
+void GeometryComponent::user_add()
+{
+  users_.fetch_add(1)

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list