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:
authorHans Goudey <h.goudey@me.com>2022-10-17 21:22:35 +0300
committerHans Goudey <h.goudey@me.com>2022-10-17 21:22:35 +0300
commitb280dce0a489720fb86820666317506c5fba50cd (patch)
tree3662a1b556e49ddf2f5396f7a3548e4e0c3b8ee2 /source/blender/blenkernel
parent70ed39518e600f4478328fc44d9a683812532003 (diff)
parente8291f4504d320ea1eac0601a9b99263fbf305e8 (diff)
Merge branch 'master' into node-add-asset-menu
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_bvhutils.h10
-rw-r--r--source/blender/blenkernel/BKE_customdata.h26
-rw-r--r--source/blender/blenkernel/BKE_editmesh_cache.h20
-rw-r--r--source/blender/blenkernel/BKE_geometry_fields.hh13
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh251
-rw-r--r--source/blender/blenkernel/BKE_instances.hh270
-rw-r--r--source/blender/blenkernel/BKE_mesh_mapping.h4
-rw-r--r--source/blender/blenkernel/BKE_mesh_runtime.h19
-rw-r--r--source/blender/blenkernel/BKE_mesh_types.h146
-rw-r--r--source/blender/blenkernel/BKE_node.h6
-rw-r--r--source/blender/blenkernel/BKE_paint.h14
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h6
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.cc36
-rw-r--r--source/blender/blenkernel/intern/appdir.c30
-rw-r--r--source/blender/blenkernel/intern/asset_catalog.cc11
-rw-r--r--source/blender/blenkernel/intern/asset_catalog_test.cc76
-rw-r--r--source/blender/blenkernel/intern/asset_library_service_test.cc7
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c2
-rw-r--r--source/blender/blenkernel/intern/blendfile.c4
-rw-r--r--source/blender/blenkernel/intern/bpath.c4
-rw-r--r--source/blender/blenkernel/intern/bvhutils.cc14
-rw-r--r--source/blender/blenkernel/intern/cloth.c2
-rw-r--r--source/blender/blenkernel/intern/customdata.cc40
-rw-r--r--source/blender/blenkernel/intern/editmesh.cc6
-rw-r--r--source/blender/blenkernel/intern/fluid.c15
-rw-r--r--source/blender/blenkernel/intern/geometry_component_instances.cc385
-rw-r--r--source/blender/blenkernel/intern/geometry_fields.cc16
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc58
-rw-r--r--source/blender/blenkernel/intern/geometry_set_instances.cc45
-rw-r--r--source/blender/blenkernel/intern/image.cc4
-rw-r--r--source/blender/blenkernel/intern/image_save.cc4
-rw-r--r--source/blender/blenkernel/intern/instances.cc348
-rw-r--r--source/blender/blenkernel/intern/layer.c2
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.cc2
-rw-r--r--source/blender/blenkernel/intern/mesh.cc38
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.cc2
-rw-r--r--source/blender/blenkernel/intern/mesh_debug.cc4
-rw-r--r--source/blender/blenkernel/intern/mesh_fair.cc2
-rw-r--r--source/blender/blenkernel/intern/mesh_iterators.cc32
-rw-r--r--source/blender/blenkernel/intern/mesh_mapping.cc4
-rw-r--r--source/blender/blenkernel/intern/mesh_normals.cc74
-rw-r--r--source/blender/blenkernel/intern/mesh_remap.c2
-rw-r--r--source/blender/blenkernel/intern/mesh_runtime.cc168
-rw-r--r--source/blender/blenkernel/intern/mesh_tangent.cc6
-rw-r--r--source/blender/blenkernel/intern/mesh_wrapper.cc74
-rw-r--r--source/blender/blenkernel/intern/modifier.cc8
-rw-r--r--source/blender/blenkernel/intern/multires.cc2
-rw-r--r--source/blender/blenkernel/intern/node.cc32
-rw-r--r--source/blender/blenkernel/intern/object.cc10
-rw-r--r--source/blender/blenkernel/intern/object_dupli.cc21
-rw-r--r--source/blender/blenkernel/intern/object_update.cc4
-rw-r--r--source/blender/blenkernel/intern/ocean.c2
-rw-r--r--source/blender/blenkernel/intern/packedFile.c2
-rw-r--r--source/blender/blenkernel/intern/paint.cc30
-rw-r--r--source/blender/blenkernel/intern/particle.c5
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c3
-rw-r--r--source/blender/blenkernel/intern/particle_system.c3
-rw-r--r--source/blender/blenkernel/intern/pbvh.c205
-rw-r--r--source/blender/blenkernel/intern/pointcache.c6
-rw-r--r--source/blender/blenkernel/intern/pointcloud.cc6
-rw-r--r--source/blender/blenkernel/intern/preferences.c3
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c6
-rw-r--r--source/blender/blenkernel/intern/scene.cc3
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.cc8
-rw-r--r--source/blender/blenkernel/intern/subdiv_ccg.cc2
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.cc10
-rw-r--r--source/blender/blenkernel/intern/subdiv_modifier.cc3
69 files changed, 1617 insertions, 1063 deletions
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 3c8f7d758b6..96df8f7a443 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -25,7 +25,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 3
+#define BLENDER_FILE_SUBVERSION 4
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file
diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h
index d22abd235df..a0a6ac58c58 100644
--- a/source/blender/blenkernel/BKE_bvhutils.h
+++ b/source/blender/blenkernel/BKE_bvhutils.h
@@ -11,6 +11,10 @@
#include "BLI_threads.h"
#ifdef __cplusplus
+# include <mutex>
+#endif
+
+#ifdef __cplusplus
extern "C" {
#endif
@@ -196,6 +200,8 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
BVHCacheType bvh_cache_type,
int tree_type);
+#ifdef __cplusplus
+
/**
* Builds or queries a BVH-cache for the cache BVH-tree of the request type.
*/
@@ -204,7 +210,9 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
int tree_type,
BVHCacheType bvh_cache_type,
struct BVHCache **bvh_cache_p,
- ThreadMutex *mesh_eval_mutex);
+ std::mutex *mesh_eval_mutex);
+
+#endif
/**
* Frees data allocated by a call to `bvhtree_from_editmesh_*`.
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 61f3a0e1d5e..f761e28cbb4 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -146,15 +146,6 @@ void CustomData_copy(const struct CustomData *source,
eCDAllocType alloctype,
int totelem);
-/**
- * Like #CustomData_copy but skips copying layers that are stored as flags on #BMesh.
- */
-void CustomData_copy_mesh_to_bmesh(const struct CustomData *source,
- struct CustomData *dest,
- eCustomDataMask mask,
- eCDAllocType alloctype,
- int totelem);
-
/* BMESH_TODO, not really a public function but readfile.c needs it */
void CustomData_update_typemap(struct CustomData *data);
@@ -169,15 +160,6 @@ bool CustomData_merge(const struct CustomData *source,
int totelem);
/**
- * Like #CustomData_copy but skips copying layers that are stored as flags on #BMesh.
- */
-bool CustomData_merge_mesh_to_bmesh(const struct CustomData *source,
- struct CustomData *dest,
- eCustomDataMask mask,
- eCDAllocType alloctype,
- int totelem);
-
-/**
* Reallocate custom data to a new element count. If the new size is larger, the new values use
* the #CD_CONSTRUCT behavior, so trivial types must be initialized by the caller. After being
* resized, the #CustomData does not contain any referenced layers.
@@ -197,6 +179,14 @@ bool CustomData_bmesh_merge(const struct CustomData *source,
char htype);
/**
+ * Remove layers that aren't stored in BMesh or are stored as flags on BMesh.
+ * The `layers` array of the returned #CustomData must be freed, but may be null.
+ * Used during conversion of #Mesh data to #BMesh storage format.
+ */
+CustomData CustomData_shallow_copy_remove_non_bmesh_attributes(const CustomData *src,
+ eCustomDataMask mask);
+
+/**
* NULL's all members and resets the #CustomData.typemap.
*/
void CustomData_reset(struct CustomData *data);
diff --git a/source/blender/blenkernel/BKE_editmesh_cache.h b/source/blender/blenkernel/BKE_editmesh_cache.h
index 2640356ccf6..454a07be4e3 100644
--- a/source/blender/blenkernel/BKE_editmesh_cache.h
+++ b/source/blender/blenkernel/BKE_editmesh_cache.h
@@ -11,15 +11,25 @@ extern "C" {
#endif
struct BMEditMesh;
-struct EditMeshData;
-void BKE_editmesh_cache_ensure_poly_normals(struct BMEditMesh *em, struct EditMeshData *emd);
-void BKE_editmesh_cache_ensure_vert_normals(struct BMEditMesh *em, struct EditMeshData *emd);
+typedef struct EditMeshData {
+ /** when set, \a vertexNos, polyNos are lazy initialized */
+ const float (*vertexCos)[3];
-void BKE_editmesh_cache_ensure_poly_centers(struct BMEditMesh *em, struct EditMeshData *emd);
+ /** lazy initialize (when \a vertexCos is set) */
+ float const (*vertexNos)[3];
+ float const (*polyNos)[3];
+ /** also lazy init but don't depend on \a vertexCos */
+ const float (*polyCos)[3];
+} EditMeshData;
+
+void BKE_editmesh_cache_ensure_poly_normals(struct BMEditMesh *em, EditMeshData *emd);
+void BKE_editmesh_cache_ensure_vert_normals(struct BMEditMesh *em, EditMeshData *emd);
+
+void BKE_editmesh_cache_ensure_poly_centers(struct BMEditMesh *em, EditMeshData *emd);
bool BKE_editmesh_cache_calc_minmax(struct BMEditMesh *em,
- struct EditMeshData *emd,
+ EditMeshData *emd,
float min[3],
float max[3]);
diff --git a/source/blender/blenkernel/BKE_geometry_fields.hh b/source/blender/blenkernel/BKE_geometry_fields.hh
index 988e0017f04..2eef67dba98 100644
--- a/source/blender/blenkernel/BKE_geometry_fields.hh
+++ b/source/blender/blenkernel/BKE_geometry_fields.hh
@@ -75,14 +75,14 @@ class PointCloudFieldContext : public fn::FieldContext {
class InstancesFieldContext : public fn::FieldContext {
private:
- const InstancesComponent &instances_;
+ const Instances &instances_;
public:
- InstancesFieldContext(const InstancesComponent &instances) : instances_(instances)
+ InstancesFieldContext(const Instances &instances) : instances_(instances)
{
}
- const InstancesComponent &instances() const
+ const Instances &instances() const
{
return instances_;
}
@@ -128,13 +128,13 @@ class GeometryFieldContext : public fn::FieldContext {
const Mesh *mesh() const;
const CurvesGeometry *curves() const;
const PointCloud *pointcloud() const;
- const InstancesComponent *instances() const;
+ const Instances *instances() const;
private:
GeometryFieldContext(const Mesh &mesh, eAttrDomain domain);
GeometryFieldContext(const CurvesGeometry &curves, eAttrDomain domain);
GeometryFieldContext(const PointCloud &points);
- GeometryFieldContext(const InstancesComponent &instances);
+ GeometryFieldContext(const Instances &instances);
};
class GeometryFieldInput : public fn::FieldInput {
@@ -187,8 +187,7 @@ class InstancesFieldInput : public fn::FieldInput {
GVArray get_varray_for_context(const fn::FieldContext &context,
IndexMask mask,
ResourceScope &scope) const override;
- virtual GVArray get_varray_for_context(const InstancesComponent &instances,
- IndexMask mask) const = 0;
+ virtual GVArray get_varray_for_context(const Instances &instances, IndexMask mask) const = 0;
};
class AttributeFieldInput : public GeometryFieldInput {
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index 2ef9556afc7..b488806c8e7 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -43,6 +43,7 @@ enum class GeometryOwnershipType {
namespace blender::bke {
class ComponentAttributeProviders;
class CurvesEditHints;
+class Instances;
} // namespace blender::bke
class GeometryComponent;
@@ -246,6 +247,12 @@ struct GeometrySet {
*/
static GeometrySet create_with_curves(
Curves *curves, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Create a new geometry set that only contains the given instances.
+ */
+ static GeometrySet create_with_instances(
+ blender::bke::Instances *instances,
+ GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
/* Utility methods for access. */
/**
@@ -294,6 +301,10 @@ struct GeometrySet {
*/
const Curves *get_curves_for_read() const;
/**
+ * Returns read-only instances or null.
+ */
+ const blender::bke::Instances *get_instances_for_read() const;
+ /**
* Returns read-only curve edit hints or null.
*/
const blender::bke::CurvesEditHints *get_curve_edit_hints_for_read() const;
@@ -315,6 +326,10 @@ struct GeometrySet {
*/
Curves *get_curves_for_write();
/**
+ * Returns mutable instances or null. No ownership is transferred.
+ */
+ blender::bke::Instances *get_instances_for_write();
+ /**
* Returns mutable curve edit hints or null.
*/
blender::bke::CurvesEditHints *get_curve_edit_hints_for_write();
@@ -339,6 +354,11 @@ struct GeometrySet {
*/
void replace_curves(Curves *curves,
GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
+ * Clear the existing instances and replace them with the given one.
+ */
+ void replace_instances(blender::bke::Instances *instances,
+ GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
private:
/**
@@ -515,244 +535,35 @@ class CurveComponent : public GeometryComponent {
};
/**
- * Holds a reference to conceptually unique geometry or a pointer to object/collection data
- * that is instanced with a transform in #InstancesComponent.
- */
-class InstanceReference {
- public:
- enum class Type {
- /**
- * An empty instance. This allows an `InstanceReference` to be default constructed without
- * being in an invalid state. There might also be other use cases that we haven't explored much
- * yet (such as changing the instance later on, and "disabling" some instances).
- */
- None,
- Object,
- Collection,
- GeometrySet,
- };
-
- private:
- Type type_ = Type::None;
- /** Depending on the type this is either null, an Object or Collection pointer. */
- void *data_ = nullptr;
- std::unique_ptr<GeometrySet> geometry_set_;
-
- public:
- InstanceReference() = default;
-
- InstanceReference(Object &object) : type_(Type::Object), data_(&object)
- {
- }
-
- InstanceReference(Collection &collection) : type_(Type::Collection), data_(&collection)
- {
- }
-
- InstanceReference(GeometrySet geometry_set)
- : type_(Type::GeometrySet),
- geometry_set_(std::make_unique<GeometrySet>(std::move(geometry_set)))
- {
- }
-
- InstanceReference(const InstanceReference &other) : type_(other.type_), data_(other.data_)
- {
- if (other.geometry_set_) {
- geometry_set_ = std::make_unique<GeometrySet>(*other.geometry_set_);
- }
- }
-
- InstanceReference(InstanceReference &&other)
- : type_(other.type_), data_(other.data_), geometry_set_(std::move(other.geometry_set_))
- {
- other.type_ = Type::None;
- other.data_ = nullptr;
- }
-
- InstanceReference &operator=(const InstanceReference &other)
- {
- if (this == &other) {
- return *this;
- }
- this->~InstanceReference();
- new (this) InstanceReference(other);
- return *this;
- }
-
- InstanceReference &operator=(InstanceReference &&other)
- {
- if (this == &other) {
- return *this;
- }
- this->~InstanceReference();
- new (this) InstanceReference(std::move(other));
- return *this;
- }
-
- Type type() const
- {
- return type_;
- }
-
- Object &object() const
- {
- BLI_assert(type_ == Type::Object);
- return *(Object *)data_;
- }
-
- Collection &collection() const
- {
- BLI_assert(type_ == Type::Collection);
- return *(Collection *)data_;
- }
-
- const GeometrySet &geometry_set() const
- {
- BLI_assert(type_ == Type::GeometrySet);
- return *geometry_set_;
- }
-
- bool owns_direct_data() const
- {
- if (type_ != Type::GeometrySet) {
- /* The object and collection instances are not direct data. */
- return true;
- }
- return geometry_set_->owns_direct_data();
- }
-
- void ensure_owns_direct_data()
- {
- if (type_ != Type::GeometrySet) {
- return;
- }
- geometry_set_->ensure_owns_direct_data();
- }
-
- uint64_t hash() const
- {
- return blender::get_default_hash_2(data_, geometry_set_.get());
- }
-
- friend bool operator==(const InstanceReference &a, const InstanceReference &b)
- {
- return a.data_ == b.data_ && a.geometry_set_.get() == b.geometry_set_.get();
- }
-};
-
-/**
- * A geometry component that stores instances. The instance data can be any type described by
- * #InstanceReference. Geometry instances can even contain instances themselves, for nested
- * instancing. Each instance has an index into an array of unique instance data, and a transform.
- * The component can also store generic attributes for each instance.
- *
- * The component works differently from other geometry components in that it stores
- * data about instancing directly, rather than owning a pointer to a separate data structure.
- *
- * This component is not responsible for handling the interface to a render engine, or other
- * areas that work with all visible geometry, that is handled by the dependency graph iterator
- * (see `DEG_depsgraph_query.h`).
+ * A geometry component that stores #Instances.
*/
class InstancesComponent : public GeometryComponent {
private:
- /**
- * Indexed set containing information about the data that is instanced.
- * Actual instances store an index ("handle") into this set.
- */
- blender::VectorSet<InstanceReference> references_;
-
- /** Index into `references_`. Determines what data is instanced. */
- blender::Vector<int> instance_reference_handles_;
- /** Transformation of the instances. */
- blender::Vector<blender::float4x4> instance_transforms_;
-
- /* These almost unique ids are generated based on the `id` attribute, which might not contain
- * unique ids at all. They are *almost* unique, because under certain very unlikely
- * circumstances, they are not unique. Code using these ids should not crash when they are not
- * unique but can generally expect them to be unique. */
- mutable std::mutex almost_unique_ids_mutex_;
- mutable blender::Array<int> almost_unique_ids_;
-
- blender::bke::CustomDataAttributes attributes_;
+ blender::bke::Instances *instances_ = nullptr;
+ GeometryOwnershipType ownership_ = GeometryOwnershipType::Owned;
public:
InstancesComponent();
- ~InstancesComponent() = default;
+ ~InstancesComponent();
GeometryComponent *copy() const override;
void clear();
- void reserve(int min_capacity);
- /**
- * Resize the transform, handles, and attributes to the specified capacity.
- *
- * \note This function should be used carefully, only when it's guaranteed
- * that the data will be filled.
- */
- void resize(int capacity);
+ const blender::bke::Instances *get_for_read() const;
+ blender::bke::Instances *get_for_write();
- /**
- * Returns a handle for the given reference.
- * If the reference exists already, the handle of the existing reference is returned.
- * Otherwise a new handle is added.
- */
- int add_reference(const InstanceReference &reference);
- /**
- * Add a reference to the instance reference with an index specified by the #instance_handle
- * argument. For adding many instances, using #resize and accessing the transform array directly
- * is preferred.
- */
- void add_instance(int instance_handle, const blender::float4x4 &transform);
-
- blender::Span<InstanceReference> references() const;
- void remove_unused_references();
-
- /**
- * If references have a collection or object type, convert them into geometry instances
- * recursively. After that, the geometry sets can be edited. There may still be instances of
- * other types of they can't be converted to geometry sets.
- */
- void ensure_geometry_instances();
- /**
- * With write access to the instances component, the data in the instanced geometry sets can be
- * changed. This is a function on the component rather than each reference to ensure `const`
- * correctness for that reason.
- */
- GeometrySet &geometry_set_from_reference(int reference_index);
-
- blender::Span<int> instance_reference_handles() const;
- blender::MutableSpan<int> instance_reference_handles();
- blender::MutableSpan<blender::float4x4> instance_transforms();
- blender::Span<blender::float4x4> instance_transforms() const;
-
- int instances_num() const;
- int references_num() const;
-
- /**
- * Remove the indices that are not contained in the mask input, and remove unused instance
- * references afterwards.
- */
- void remove_instances(const blender::IndexMask mask);
-
- blender::Span<int> almost_unique_ids() const;
-
- blender::bke::CustomDataAttributes &instance_attributes();
- const blender::bke::CustomDataAttributes &instance_attributes() const;
-
- std::optional<blender::bke::AttributeAccessor> attributes() const final;
- std::optional<blender::bke::MutableAttributeAccessor> attributes_for_write() final;
-
- void foreach_referenced_geometry(
- blender::FunctionRef<void(const GeometrySet &geometry_set)> callback) const;
+ void replace(blender::bke::Instances *instances,
+ GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
bool is_empty() const final;
bool owns_direct_data() const override;
void ensure_owns_direct_data() override;
- static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_INSTANCES;
+ std::optional<blender::bke::AttributeAccessor> attributes() const final;
+ std::optional<blender::bke::MutableAttributeAccessor> attributes_for_write() final;
- private:
+ static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_INSTANCES;
};
/**
diff --git a/source/blender/blenkernel/BKE_instances.hh b/source/blender/blenkernel/BKE_instances.hh
new file mode 100644
index 00000000000..6502fefec88
--- /dev/null
+++ b/source/blender/blenkernel/BKE_instances.hh
@@ -0,0 +1,270 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+/** \file
+ * \ingroup bke
+ *
+ * #Instances is a container for geometry instances. It fullfills some key requirements:
+ * - Support nested instances.
+ * - Support instance attributes.
+ * - Support referencing different kinds of instances (objects, collections, geometry sets).
+ * - Support efficiently iterating over the instanced geometries, i.e. without have to iterate over
+ * all instances.
+ *
+ * #Instances has an ordered set of #InstanceReference. An #InstanceReference contains information
+ * about a particular instanced geometry. Each #InstanceReference has a handle (integer index)
+ * which is then stored per instance. Many instances can use the same #InstanceReference.
+ */
+
+#include <mutex>
+
+#include "BLI_float4x4.hh"
+#include "BLI_vector.hh"
+#include "BLI_vector_set.hh"
+
+#include "BKE_attribute.hh"
+
+struct GeometrySet;
+struct Object;
+struct Collection;
+
+namespace blender::bke {
+
+/**
+ * Holds a reference to conceptually unique geometry or a pointer to object/collection data
+ * that is instanced with a transform in #Instances.
+ */
+class InstanceReference {
+ public:
+ enum class Type {
+ /**
+ * An empty instance. This allows an `InstanceReference` to be default constructed without
+ * being in an invalid state. There might also be other use cases that we haven't explored
+ * much yet (such as changing the instance later on, and "disabling" some instances).
+ */
+ None,
+ Object,
+ Collection,
+ GeometrySet,
+ };
+
+ private:
+ Type type_ = Type::None;
+ /** Depending on the type this is either null, an Object or Collection pointer. */
+ void *data_ = nullptr;
+ std::unique_ptr<GeometrySet> geometry_set_;
+
+ public:
+ InstanceReference() = default;
+ InstanceReference(Object &object);
+ InstanceReference(Collection &collection);
+ InstanceReference(GeometrySet geometry_set);
+
+ InstanceReference(const InstanceReference &other);
+ InstanceReference(InstanceReference &&other);
+
+ InstanceReference &operator=(const InstanceReference &other);
+ InstanceReference &operator=(InstanceReference &&other);
+
+ Type type() const;
+ Object &object() const;
+ Collection &collection() const;
+ const GeometrySet &geometry_set() const;
+
+ bool owns_direct_data() const;
+ void ensure_owns_direct_data();
+
+ uint64_t hash() const;
+ friend bool operator==(const InstanceReference &a, const InstanceReference &b);
+};
+
+class Instances {
+ private:
+ /**
+ * Indexed set containing information about the data that is instanced.
+ * Actual instances store an index ("handle") into this set.
+ */
+ blender::VectorSet<InstanceReference> references_;
+
+ /** Indices into `references_`. Determines what data is instanced. */
+ blender::Vector<int> reference_handles_;
+ /** Transformation of the instances. */
+ blender::Vector<blender::float4x4> transforms_;
+
+ /* These almost unique ids are generated based on the `id` attribute, which might not contain
+ * unique ids at all. They are *almost* unique, because under certain very unlikely
+ * circumstances, they are not unique. Code using these ids should not crash when they are not
+ * unique but can generally expect them to be unique. */
+ mutable std::mutex almost_unique_ids_mutex_;
+ mutable blender::Array<int> almost_unique_ids_;
+
+ CustomDataAttributes attributes_;
+
+ public:
+ Instances() = default;
+ Instances(const Instances &other);
+
+ void reserve(int min_capacity);
+ /**
+ * Resize the transform, handles, and attributes to the specified capacity.
+ *
+ * \note This function should be used carefully, only when it's guaranteed
+ * that the data will be filled.
+ */
+ void resize(int capacity);
+
+ /**
+ * Returns a handle for the given reference.
+ * If the reference exists already, the handle of the existing reference is returned.
+ * Otherwise a new handle is added.
+ */
+ int add_reference(const InstanceReference &reference);
+ /**
+ * Add a reference to the instance reference with an index specified by the #instance_handle
+ * argument. For adding many instances, using #resize and accessing the transform array
+ * directly is preferred.
+ */
+ void add_instance(int instance_handle, const blender::float4x4 &transform);
+
+ blender::Span<InstanceReference> references() const;
+ void remove_unused_references();
+
+ /**
+ * If references have a collection or object type, convert them into geometry instances
+ * recursively. After that, the geometry sets can be edited. There may still be instances of
+ * other types of they can't be converted to geometry sets.
+ */
+ void ensure_geometry_instances();
+ /**
+ * With write access to the instances component, the data in the instanced geometry sets can be
+ * changed. This is a function on the component rather than each reference to ensure `const`
+ * correctness for that reason.
+ */
+ GeometrySet &geometry_set_from_reference(int reference_index);
+
+ blender::Span<int> reference_handles() const;
+ blender::MutableSpan<int> reference_handles();
+ blender::MutableSpan<blender::float4x4> transforms();
+ blender::Span<blender::float4x4> transforms() const;
+
+ int instances_num() const;
+ int references_num() const;
+
+ /**
+ * Remove the indices that are not contained in the mask input, and remove unused instance
+ * references afterwards.
+ */
+ void remove(const blender::IndexMask mask);
+ /**
+ * Get an id for every instance. These can be used for e.g. motion blur.
+ */
+ blender::Span<int> almost_unique_ids() const;
+
+ blender::bke::AttributeAccessor attributes() const;
+ blender::bke::MutableAttributeAccessor attributes_for_write();
+
+ CustomDataAttributes &custom_data_attributes();
+ const CustomDataAttributes &custom_data_attributes() const;
+
+ void foreach_referenced_geometry(
+ blender::FunctionRef<void(const GeometrySet &geometry_set)> callback) const;
+
+ bool owns_direct_data() const;
+ void ensure_owns_direct_data();
+};
+
+/* -------------------------------------------------------------------- */
+/** \name #InstanceReference Inline Methods
+ * \{ */
+
+inline InstanceReference::InstanceReference(Object &object) : type_(Type::Object), data_(&object)
+{
+}
+
+inline InstanceReference::InstanceReference(Collection &collection)
+ : type_(Type::Collection), data_(&collection)
+{
+}
+
+inline InstanceReference::InstanceReference(const InstanceReference &other)
+ : type_(other.type_), data_(other.data_)
+{
+ if (other.geometry_set_) {
+ geometry_set_ = std::make_unique<GeometrySet>(*other.geometry_set_);
+ }
+}
+
+inline InstanceReference::InstanceReference(InstanceReference &&other)
+ : type_(other.type_), data_(other.data_), geometry_set_(std::move(other.geometry_set_))
+{
+ other.type_ = Type::None;
+ other.data_ = nullptr;
+}
+
+inline InstanceReference &InstanceReference::operator=(const InstanceReference &other)
+{
+ if (this == &other) {
+ return *this;
+ }
+ this->~InstanceReference();
+ new (this) InstanceReference(other);
+ return *this;
+}
+
+inline InstanceReference &InstanceReference::operator=(InstanceReference &&other)
+{
+ if (this == &other) {
+ return *this;
+ }
+ this->~InstanceReference();
+ new (this) InstanceReference(std::move(other));
+ return *this;
+}
+
+inline InstanceReference::Type InstanceReference::type() const
+{
+ return type_;
+}
+
+inline Object &InstanceReference::object() const
+{
+ BLI_assert(type_ == Type::Object);
+ return *(Object *)data_;
+}
+
+inline Collection &InstanceReference::collection() const
+{
+ BLI_assert(type_ == Type::Collection);
+ return *(Collection *)data_;
+}
+
+inline const GeometrySet &InstanceReference::geometry_set() const
+{
+ BLI_assert(type_ == Type::GeometrySet);
+ return *geometry_set_;
+}
+
+inline CustomDataAttributes &Instances::custom_data_attributes()
+{
+ return attributes_;
+}
+
+inline const CustomDataAttributes &Instances::custom_data_attributes() const
+{
+ return attributes_;
+}
+
+inline uint64_t InstanceReference::hash() const
+{
+ return blender::get_default_hash_2(data_, geometry_set_.get());
+}
+
+inline bool operator==(const InstanceReference &a, const InstanceReference &b)
+{
+ return a.data_ == b.data_ && a.geometry_set_.get() == b.geometry_set_.get();
+}
+
+/** \} */
+
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h
index da8431d4f27..9d9c2f57f89 100644
--- a/source/blender/blenkernel/BKE_mesh_mapping.h
+++ b/source/blender/blenkernel/BKE_mesh_mapping.h
@@ -336,7 +336,7 @@ int *BKE_mesh_calc_smoothgroups(const struct MEdge *medge,
#endif
#ifdef __cplusplus
-namespace blender::mesh_topology {
+namespace blender::bke::mesh_topology {
Array<int> build_loop_to_poly_map(Span<MPoly> polys, int loops_num);
@@ -348,5 +348,5 @@ inline int previous_poly_loop(const MPoly &poly, int loop_i)
return loop_i - 1 + (loop_i == poly.loopstart) * poly.totloop;
}
-} // namespace blender::mesh_topology
+} // namespace blender::bke::mesh_topology
#endif
diff --git a/source/blender/blenkernel/BKE_mesh_runtime.h b/source/blender/blenkernel/BKE_mesh_runtime.h
index dfefe125a51..27e04c1a4de 100644
--- a/source/blender/blenkernel/BKE_mesh_runtime.h
+++ b/source/blender/blenkernel/BKE_mesh_runtime.h
@@ -9,6 +9,7 @@
*/
//#include "BKE_customdata.h" /* for eCustomDataMask */
+#include "BKE_mesh_types.h"
#ifdef __cplusplus
extern "C" {
@@ -26,21 +27,10 @@ struct Object;
struct Scene;
/**
- * \brief Initialize the runtime of the given mesh.
- *
- * Function expects that the runtime is already cleared.
- */
-void BKE_mesh_runtime_init_data(struct Mesh *mesh);
-/**
* \brief Free all data (and mutexes) inside the runtime of the given mesh.
*/
void BKE_mesh_runtime_free_data(struct Mesh *mesh);
-/**
- * Clear all pointers which we don't want to be shared on copying the datablock.
- * However, keep all the flags which defines what the mesh is (for example, that
- * it's deformed only, or that its custom data layers are out of date.)
- */
-void BKE_mesh_runtime_reset_on_copy(struct Mesh *mesh, int flag);
+
int BKE_mesh_runtime_looptri_len(const struct Mesh *mesh);
void BKE_mesh_runtime_looptri_recalc(struct Mesh *mesh);
/**
@@ -66,6 +56,11 @@ void BKE_mesh_runtime_verttri_from_looptri(struct MVertTri *r_verttri,
const struct MLoopTri *looptri,
int looptri_num);
+/** \note Only used for access in C. */
+bool BKE_mesh_is_deformed_only(const struct Mesh *mesh);
+/** \note Only used for access in C. */
+eMeshWrapperType BKE_mesh_wrapper_type(const struct Mesh *mesh);
+
/* NOTE: the functions below are defined in DerivedMesh.cc, and are intended to be moved
* to a more suitable location when that file is removed.
* They should also be renamed to use conventions from BKE, not old DerivedMesh.cc.
diff --git a/source/blender/blenkernel/BKE_mesh_types.h b/source/blender/blenkernel/BKE_mesh_types.h
index 0b879c1dfe9..80f61086052 100644
--- a/source/blender/blenkernel/BKE_mesh_types.h
+++ b/source/blender/blenkernel/BKE_mesh_types.h
@@ -1,11 +1,35 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2020 Blender Foundation. All rights reserved. */
+
#pragma once
/** \file
* \ingroup bke
*/
+#ifdef __cplusplus
+
+# include <mutex>
+
+# include "BLI_span.hh"
+
+# include "DNA_customdata_types.h"
+
+# include "MEM_guardedalloc.h"
+
+struct BVHCache;
+struct EditMeshData;
+struct MLoopTri;
+struct ShrinkwrapBoundaryData;
+struct SubdivCCG;
+struct SubsurfRuntimeData;
+
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef enum eMeshBatchDirtyMode {
BKE_MESH_BATCH_DIRTY_ALL = 0,
BKE_MESH_BATCH_DIRTY_SELECT,
@@ -14,3 +38,125 @@ typedef enum eMeshBatchDirtyMode {
BKE_MESH_BATCH_DIRTY_UVEDIT_ALL,
BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT,
} eMeshBatchDirtyMode;
+
+/** #MeshRuntime.wrapper_type */
+typedef enum eMeshWrapperType {
+ /** Use mesh data (#Mesh.mvert, #Mesh.medge, #Mesh.mloop, #Mesh.mpoly). */
+ ME_WRAPPER_TYPE_MDATA = 0,
+ /** Use edit-mesh data (#Mesh.edit_mesh, #MeshRuntime.edit_data). */
+ ME_WRAPPER_TYPE_BMESH = 1,
+ /** Use subdivision mesh data (#MeshRuntime.mesh_eval). */
+ ME_WRAPPER_TYPE_SUBD = 2,
+} eMeshWrapperType;
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+
+namespace blender::bke {
+
+/**
+ * \warning Typical access is done via #Mesh::looptris().
+ */
+struct MLoopTri_Store {
+ /* WARNING! swapping between array (ready-to-be-used data) and array_wip
+ * (where data is actually computed)
+ * shall always be protected by same lock as one used for looptris computing. */
+ MLoopTri *array = nullptr;
+ MLoopTri *array_wip = nullptr;
+ int len = 0;
+ int len_alloc = 0;
+};
+
+struct MeshRuntime {
+ /* Evaluated mesh for objects which do not have effective modifiers.
+ * This mesh is used as a result of modifier stack evaluation.
+ * Since modifier stack evaluation is threaded on object level we need some synchronization. */
+ Mesh *mesh_eval = nullptr;
+ std::mutex eval_mutex;
+
+ /* A separate mutex is needed for normal calculation, because sometimes
+ * the normals are needed while #eval_mutex is already locked. */
+ std::mutex normals_mutex;
+
+ /** Needed to ensure some thread-safety during render data pre-processing. */
+ std::mutex render_mutex;
+
+ /** Lazily initialized SoA data from the #edit_mesh field in #Mesh. */
+ EditMeshData *edit_data = nullptr;
+
+ /**
+ * Data used to efficiently draw the mesh in the viewport, especially useful when
+ * the same mesh is used in many objects or instances. See `draw_cache_impl_mesh.cc`.
+ */
+ void *batch_cache = nullptr;
+
+ /** Cache for derived triangulation of the mesh. */
+ MLoopTri_Store looptris;
+
+ /** Cache for BVH trees generated for the mesh. Defined in 'BKE_bvhutil.c' */
+ BVHCache *bvh_cache = nullptr;
+
+ /** Cache of non-manifold boundary data for Shrink-wrap Target Project. */
+ ShrinkwrapBoundaryData *shrinkwrap_data = nullptr;
+
+ /** Needed in case we need to lazily initialize the mesh. */
+ CustomData_MeshMasks cd_mask_extra = {};
+
+ SubdivCCG *subdiv_ccg = nullptr;
+ int subdiv_ccg_tot_level = 0;
+
+ /** Set by modifier stack if only deformed from original. */
+ bool deformed_only = false;
+ /**
+ * Copied from edit-mesh (hint, draw with edit-mesh data when true).
+ *
+ * Modifiers that edit the mesh data in-place must set this to false
+ * (most #eModifierTypeType_NonGeometrical modifiers). Otherwise the edit-mesh
+ * data will be used for drawing, missing changes from modifiers. See T79517.
+ */
+ bool is_original_bmesh = false;
+
+ /** #eMeshWrapperType and others. */
+ eMeshWrapperType wrapper_type = ME_WRAPPER_TYPE_MDATA;
+ /**
+ * A type mask from wrapper_type,
+ * in case there are differences in finalizing logic between types.
+ */
+ eMeshWrapperType wrapper_type_finalize = ME_WRAPPER_TYPE_MDATA;
+
+ /**
+ * Settings for lazily evaluating the subdivision on the CPU if needed. These are
+ * set in the modifier when GPU subdivision can be performed, and owned by the by
+ * the modifier in the object.
+ */
+ SubsurfRuntimeData *subsurf_runtime_data = nullptr;
+
+ /**
+ * Caches for lazily computed vertex and polygon normals. These are stored here rather than in
+ * #CustomData because they can be calculated on a `const` mesh, and adding custom data layers on
+ * a `const` mesh is not thread-safe.
+ */
+ bool vert_normals_dirty = false;
+ bool poly_normals_dirty = false;
+ float (*vert_normals)[3] = nullptr;
+ float (*poly_normals)[3] = nullptr;
+
+ /**
+ * A #BLI_bitmap containing tags for the center vertices of subdivided polygons, set by the
+ * subdivision surface modifier and used by drawing code instead of polygon center face dots.
+ */
+ uint32_t *subsurf_face_dot_tags = nullptr;
+
+ MeshRuntime() = default;
+ /** \warning This does not free all data currently. See #BKE_mesh_runtime_free_data. */
+ ~MeshRuntime() = default;
+
+ MEM_CXX_CLASS_ALLOC_FUNCS("MeshRuntime")
+};
+
+} // namespace blender::bke
+
+#endif
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index b1b4045370c..ecf7a556459 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -792,6 +792,12 @@ void nodeChainIterBackwards(const bNodeTree *ntree,
*/
void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userdata);
+/**
+ * A dangling reroute node is a reroute node that does *not* have a "data source", i.e. no
+ * non-reroute node is connected to its input.
+ */
+bool nodeIsDanglingReroute(const struct bNodeTree *ntree, const struct bNode *node);
+
struct bNodeLink *nodeFindLink(struct bNodeTree *ntree,
const struct bNodeSocket *from,
const struct bNodeSocket *to);
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 5312292d431..437a22e4782 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -860,7 +860,19 @@ int *BKE_sculpt_face_sets_ensure(struct Mesh *mesh);
* (see #SCULPT_visibility_sync_all_from_faces).
*/
bool *BKE_sculpt_hide_poly_ensure(struct Mesh *mesh);
-int BKE_sculpt_mask_layers_ensure(struct Object *ob, struct MultiresModifierData *mmd);
+
+/**
+ * Ensures a mask layer exists. If depsgraph and bmain are non-null,
+ * a mask doesn't exist and the object has a multi-resolution modifier
+ * then the scene depsgraph will be evaluated to update the runtime
+ * subdivision data.
+ *
+ * \note always call *before* #BKE_sculpt_update_object_for_edit.
+ */
+int BKE_sculpt_mask_layers_ensure(struct Depsgraph *depsgraph,
+ struct Main *bmain,
+ struct Object *ob,
+ struct MultiresModifierData *mmd);
void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene);
struct PBVH *BKE_sculpt_object_pbvh_ensure(struct Depsgraph *depsgraph, struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 89743f1d2b4..b375d69b61c 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -267,7 +267,8 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
void **gridfaces,
struct DMFlagMat *flagmats,
unsigned int **grid_hidden,
- struct Mesh *me);
+ struct Mesh *me,
+ struct SubdivCCG *subdiv_ccg);
/**
* Build a PBVH from a BMesh.
*/
@@ -504,7 +505,8 @@ void BKE_pbvh_grids_update(PBVH *pbvh,
struct CCGElem **grids,
void **gridfaces,
struct DMFlagMat *flagmats,
- unsigned int **grid_hidden);
+ unsigned int **grid_hidden,
+ struct CCGKey *key);
void BKE_pbvh_subdiv_cgg_set(PBVH *pbvh, struct SubdivCCG *subdiv_ccg);
void BKE_pbvh_face_sets_set(PBVH *pbvh, int *face_sets);
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 97bdff217d0..7d43fa7e6af 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -163,6 +163,7 @@ set(SRC
intern/image_gpu.cc
intern/image_partial_update.cc
intern/image_save.cc
+ intern/instances.cc
intern/ipo.c
intern/kelvinlet.c
intern/key.c
@@ -398,6 +399,7 @@ set(SRC
BKE_image_partial_update.hh
BKE_image_save.h
BKE_image_wrappers.hh
+ BKE_instances.hh
BKE_ipo.h
BKE_kelvinlet.h
BKE_key.h
diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc
index 742f20fa65f..11ef2b08df4 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.cc
+++ b/source/blender/blenkernel/intern/DerivedMesh.cc
@@ -35,6 +35,7 @@
#include "BKE_colorband.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.h"
#include "BKE_geometry_set.hh"
#include "BKE_geometry_set_instances.hh"
#include "BKE_key.h"
@@ -537,7 +538,7 @@ static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
(final_datamask->lmask & CD_MASK_NORMAL) != 0);
/* Needed as `final_datamask` is not preserved outside modifier stack evaluation. */
- SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime.subsurf_runtime_data;
+ SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime->subsurf_runtime_data;
if (subsurf_runtime_data) {
subsurf_runtime_data->calc_loop_normals = calc_loop_normals;
}
@@ -585,11 +586,12 @@ static void mesh_calc_finalize(const Mesh *mesh_input, Mesh *mesh_eval)
void BKE_mesh_wrapper_deferred_finalize_mdata(Mesh *me_eval,
const CustomData_MeshMasks *cd_mask_finalize)
{
- if (me_eval->runtime.wrapper_type_finalize & (1 << ME_WRAPPER_TYPE_BMESH)) {
+ if (me_eval->runtime->wrapper_type_finalize & (1 << ME_WRAPPER_TYPE_BMESH)) {
editbmesh_calc_modifier_final_normals(me_eval, cd_mask_finalize);
- me_eval->runtime.wrapper_type_finalize &= ~(1 << ME_WRAPPER_TYPE_BMESH);
+ me_eval->runtime->wrapper_type_finalize = eMeshWrapperType(
+ me_eval->runtime->wrapper_type_finalize & ~(1 << ME_WRAPPER_TYPE_BMESH));
}
- BLI_assert(me_eval->runtime.wrapper_type_finalize == 0);
+ BLI_assert(me_eval->runtime->wrapper_type_finalize == 0);
}
/**
@@ -1052,7 +1054,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
append_mask.lmask |= CD_MASK_PREVIEW_MLOOPCOL;
}
- mesh_final->runtime.deformed_only = false;
+ mesh_final->runtime->deformed_only = false;
}
isPrevDeform = (mti->type == eModifierTypeType_OnlyDeform);
@@ -1119,10 +1121,9 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
mesh_calc_finalize(mesh_input, mesh_final);
}
else {
- Mesh_Runtime *runtime = &mesh_input->runtime;
+ blender::bke::MeshRuntime *runtime = mesh_input->runtime;
if (runtime->mesh_eval == nullptr) {
- BLI_assert(runtime->eval_mutex != nullptr);
- BLI_mutex_lock((ThreadMutex *)runtime->eval_mutex);
+ std::lock_guard lock{mesh_input->runtime->eval_mutex};
if (runtime->mesh_eval == nullptr) {
/* Not yet finalized by any instance, do it now
* Isolate since computing normals is multithreaded and we are holding a lock. */
@@ -1138,7 +1139,6 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
/* Already finalized by another instance, reuse. */
mesh_final = runtime->mesh_eval;
}
- BLI_mutex_unlock((ThreadMutex *)runtime->eval_mutex);
}
else if (!mesh_has_modifier_final_normals(mesh_input, &final_datamask, runtime->mesh_eval)) {
/* Modifier stack was (re-)evaluated with a request for additional normals
@@ -1207,7 +1207,7 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
const bool calc_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 ||
(final_datamask->lmask & CD_MASK_NORMAL) != 0);
- SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime.subsurf_runtime_data;
+ SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime->subsurf_runtime_data;
if (subsurf_runtime_data) {
subsurf_runtime_data->calc_loop_normals = calc_loop_normals;
}
@@ -1234,9 +1234,10 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
static void editbmesh_calc_modifier_final_normals_or_defer(
Mesh *mesh_final, const CustomData_MeshMasks *final_datamask)
{
- if (mesh_final->runtime.wrapper_type != ME_WRAPPER_TYPE_MDATA) {
+ if (mesh_final->runtime->wrapper_type != ME_WRAPPER_TYPE_MDATA) {
/* Generated at draw time. */
- mesh_final->runtime.wrapper_type_finalize = (1 << mesh_final->runtime.wrapper_type);
+ mesh_final->runtime->wrapper_type_finalize = eMeshWrapperType(
+ 1 << mesh_final->runtime->wrapper_type);
return;
}
@@ -1450,7 +1451,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
deformed_verts = nullptr;
}
}
- mesh_final->runtime.deformed_only = false;
+ mesh_final->runtime->deformed_only = false;
}
if (r_cage && i == cageIndex) {
@@ -1469,7 +1470,8 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
if (!BKE_mesh_runtime_ensure_edit_data(me_orig)) {
BKE_mesh_runtime_reset_edit_data(me_orig);
}
- me_orig->runtime.edit_data->vertexCos = (const float(*)[3])MEM_dupallocN(deformed_verts);
+ me_orig->runtime->edit_data->vertexCos = (const float(*)[3])MEM_dupallocN(
+ deformed_verts);
}
mesh_cage = BKE_mesh_wrapper_from_editmesh_with_coords(
em_input,
@@ -1583,7 +1585,7 @@ static void mesh_build_data(struct Depsgraph *depsgraph,
* object's runtime: this could cause access freed data on depsgraph destruction (mesh who owns
* the final result might be freed prior to object). */
Mesh *mesh = (Mesh *)ob->data;
- const bool is_mesh_eval_owned = (mesh_eval != mesh->runtime.mesh_eval);
+ const bool is_mesh_eval_owned = (mesh_eval != mesh->runtime->mesh_eval);
BKE_object_eval_assign_data(ob, &mesh_eval->id, is_mesh_eval_owned);
/* Add the final mesh as a non-owning component to the geometry set. */
@@ -1643,7 +1645,7 @@ static void editbmesh_build_data(struct Depsgraph *depsgraph,
}
}
- const bool is_mesh_eval_owned = (me_final != mesh->runtime.mesh_eval);
+ const bool is_mesh_eval_owned = (me_final != mesh->runtime->mesh_eval);
BKE_object_eval_assign_data(obedit, &me_final->id, is_mesh_eval_owned);
obedit->runtime.editmesh_eval_cage = me_cage;
@@ -1914,7 +1916,7 @@ static void make_vertexcos__mapFunc(void *userData,
void mesh_get_mapped_verts_coords(Mesh *me_eval, float (*r_cos)[3], const int totcos)
{
- if (me_eval->runtime.deformed_only == false) {
+ if (me_eval->runtime->deformed_only == false) {
MappedUserData userData;
memset(r_cos, 0, sizeof(*r_cos) * totcos);
userData.vertexcos = r_cos;
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index b2f1e75cd1d..965f48d1e51 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -191,7 +191,7 @@ bool BKE_appdir_folder_documents(char *dir)
char try_documents_path[FILE_MAXDIR];
/* Own attempt at getting a valid Documents path. */
- BLI_path_join(try_documents_path, sizeof(try_documents_path), home_path, N_("Documents"), NULL);
+ BLI_path_join(try_documents_path, sizeof(try_documents_path), home_path, N_("Documents"));
if (!BLI_is_dir(try_documents_path)) {
return false;
}
@@ -214,11 +214,11 @@ bool BKE_appdir_folder_caches(char *r_path, const size_t path_len)
#ifdef WIN32
BLI_path_join(
- r_path, path_len, caches_root_path, "Blender Foundation", "Blender", "Cache", SEP_STR, NULL);
+ r_path, path_len, caches_root_path, "Blender Foundation", "Blender", "Cache", SEP_STR);
#elif defined(__APPLE__)
- BLI_path_join(r_path, path_len, caches_root_path, "Blender", SEP_STR, NULL);
+ BLI_path_join(r_path, path_len, caches_root_path, "Blender", SEP_STR);
#else /* __linux__ */
- BLI_path_join(r_path, path_len, caches_root_path, "blender", SEP_STR, NULL);
+ BLI_path_join(r_path, path_len, caches_root_path, "blender", SEP_STR);
#endif
return true;
@@ -281,7 +281,9 @@ static bool test_path(char *targetpath,
/* Only the last argument should be NULL. */
BLI_assert(!(folder_name == NULL && (subfolder_name != NULL)));
- BLI_path_join(targetpath, targetpath_len, path_base, folder_name, subfolder_name, NULL);
+ const char *path_array[] = {path_base, folder_name, subfolder_name};
+ const int path_array_num = (folder_name ? (subfolder_name ? 3 : 2) : 1);
+ BLI_path_join_array(targetpath, targetpath_len, path_array, path_array_num);
if (check_is_dir == false) {
CLOG_INFO(&LOG, 3, "using without test: '%s'", targetpath);
return true;
@@ -365,7 +367,9 @@ static bool get_path_local_ex(char *targetpath,
STR_OR_FALLBACK(subfolder_name));
if (folder_name) { /* `subfolder_name` may be NULL. */
- BLI_path_join(relfolder, sizeof(relfolder), folder_name, subfolder_name, NULL);
+ const char *path_array[] = {folder_name, subfolder_name};
+ const int path_array_num = subfolder_name ? 2 : 1;
+ BLI_path_join_array(relfolder, sizeof(relfolder), path_array, path_array_num);
}
else {
relfolder[0] = '\0';
@@ -379,8 +383,7 @@ static bool get_path_local_ex(char *targetpath,
* we must move the blender_version dir with contents to Resources.
* Add 4 + 9 for the temporary `/../` path & `Resources`. */
char osx_resourses[FILE_MAX + 4 + 9];
- BLI_path_join(
- osx_resourses, sizeof(osx_resourses), g_app.program_dirname, "..", "Resources", NULL);
+ BLI_path_join(osx_resourses, sizeof(osx_resourses), g_app.program_dirname, "..", "Resources");
/* Remove the '/../' added above. */
BLI_path_normalize(NULL, osx_resourses);
path_base = osx_resourses;
@@ -525,7 +528,9 @@ static bool get_path_system_ex(char *targetpath,
char relfolder[FILE_MAX];
if (folder_name) { /* `subfolder_name` may be NULL. */
- BLI_path_join(relfolder, sizeof(relfolder), folder_name, subfolder_name, NULL);
+ const char *path_array[] = {folder_name, subfolder_name};
+ const int path_array_num = subfolder_name ? 2 : 1;
+ BLI_path_join_array(relfolder, sizeof(relfolder), path_array, path_array_num);
}
else {
relfolder[0] = '\0';
@@ -949,7 +954,7 @@ bool BKE_appdir_program_python_search(char *fullpath,
if (python_bin_dir) {
for (int i = 0; i < ARRAY_SIZE(python_names); i++) {
- BLI_join_dirfile(fullpath, fullpath_len, python_bin_dir, python_names[i]);
+ BLI_path_join(fullpath, fullpath_len, python_bin_dir, python_names[i]);
if (
#ifdef _WIN32
@@ -1018,7 +1023,7 @@ bool BKE_appdir_app_template_id_search(const char *app_template, char *path, siz
{
for (int i = 0; i < ARRAY_SIZE(app_template_directory_id); i++) {
char subdir[FILE_MAX];
- BLI_join_dirfile(subdir, sizeof(subdir), app_template_directory_search[i], app_template);
+ BLI_path_join(subdir, sizeof(subdir), app_template_directory_search[i], app_template);
if (BKE_appdir_folder_id_ex(app_template_directory_id[i], subdir, path, path_len)) {
return true;
}
@@ -1041,8 +1046,7 @@ bool BKE_appdir_app_template_has_userpref(const char *app_template)
}
char userpref_path[FILE_MAX];
- BLI_path_join(
- userpref_path, sizeof(userpref_path), app_template_path, BLENDER_USERPREF_FILE, NULL);
+ BLI_path_join(userpref_path, sizeof(userpref_path), app_template_path, BLENDER_USERPREF_FILE);
return BLI_exists(userpref_path);
}
diff --git a/source/blender/blenkernel/intern/asset_catalog.cc b/source/blender/blenkernel/intern/asset_catalog.cc
index 8a28e209c6a..62d03b2d79b 100644
--- a/source/blender/blenkernel/intern/asset_catalog.cc
+++ b/source/blender/blenkernel/intern/asset_catalog.cc
@@ -285,10 +285,10 @@ AssetCatalog *AssetCatalogService::create_catalog(const AssetCatalogPath &catalo
static std::string asset_definition_default_file_path_from_dir(StringRef asset_library_root)
{
char file_path[PATH_MAX];
- BLI_join_dirfile(file_path,
- sizeof(file_path),
- asset_library_root.data(),
- AssetCatalogService::DEFAULT_CATALOG_FILENAME.data());
+ BLI_path_join(file_path,
+ sizeof(file_path),
+ asset_library_root.data(),
+ AssetCatalogService::DEFAULT_CATALOG_FILENAME.data());
return file_path;
}
@@ -516,8 +516,7 @@ CatalogFilePath AssetCatalogService::find_suitable_cdf_path_for_writing(
BLI_path_join(asset_lib_cdf_path,
sizeof(asset_lib_cdf_path),
suitable_root_path,
- DEFAULT_CATALOG_FILENAME.c_str(),
- nullptr);
+ DEFAULT_CATALOG_FILENAME.c_str());
return asset_lib_cdf_path;
}
diff --git a/source/blender/blenkernel/intern/asset_catalog_test.cc b/source/blender/blenkernel/intern/asset_catalog_test.cc
index 81eb1786322..ee2dd652b61 100644
--- a/source/blender/blenkernel/intern/asset_catalog_test.cc
+++ b/source/blender/blenkernel/intern/asset_catalog_test.cc
@@ -98,7 +98,7 @@ class AssetCatalogTest : public testing::Test {
FAIL();
}
- asset_library_root_ = test_files_dir + "/" + "asset_library";
+ asset_library_root_ = test_files_dir + SEP_STR + "asset_library";
temp_library_path_ = "";
}
@@ -116,7 +116,7 @@ class AssetCatalogTest : public testing::Test {
{
BKE_tempdir_init("");
const CatalogFilePath tempdir = BKE_tempdir_session();
- temp_library_path_ = tempdir + "test-temporary-path/";
+ temp_library_path_ = tempdir + "test-temporary-path" + SEP_STR;
return temp_library_path_;
}
@@ -202,9 +202,10 @@ class AssetCatalogTest : public testing::Test {
void save_from_memory_into_existing_asset_lib(const bool should_top_level_cdf_exist)
{
const CatalogFilePath target_dir = create_temp_path(); /* Has trailing slash. */
- const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt";
- const CatalogFilePath registered_asset_lib = target_dir + "my_asset_library/";
- const CatalogFilePath asset_lib_subdir = registered_asset_lib + "subdir/";
+ const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR +
+ "blender_assets.cats.txt";
+ const CatalogFilePath registered_asset_lib = target_dir + "my_asset_library" + SEP_STR;
+ const CatalogFilePath asset_lib_subdir = registered_asset_lib + "subdir" + SEP_STR;
CatalogFilePath cdf_toplevel = registered_asset_lib +
AssetCatalogService::DEFAULT_CATALOG_FILENAME;
CatalogFilePath cdf_in_subdir = asset_lib_subdir +
@@ -272,7 +273,7 @@ class AssetCatalogTest : public testing::Test {
TEST_F(AssetCatalogTest, load_single_file)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+ service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
/* Test getting a non-existent catalog ID. */
EXPECT_EQ(nullptr, service.find_catalog(BLI_uuid_generate_random()));
@@ -313,7 +314,7 @@ TEST_F(AssetCatalogTest, load_single_file)
TEST_F(AssetCatalogTest, load_catalog_path_backslashes)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+ service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
const AssetCatalog *found_by_id = service.find_catalog(UUID_POSES_ELLIE_BACKSLASHES);
ASSERT_NE(nullptr, found_by_id);
@@ -332,7 +333,7 @@ TEST_F(AssetCatalogTest, load_catalog_path_backslashes)
TEST_F(AssetCatalogTest, is_first_loaded_flag)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+ service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
AssetCatalog *new_cat = service.create_catalog("never/before/seen/path");
EXPECT_FALSE(new_cat->flags.is_first_loaded)
@@ -435,7 +436,7 @@ TEST_F(AssetCatalogTest, insert_item_into_tree)
TEST_F(AssetCatalogTest, load_single_file_into_tree)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+ service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
/* Contains not only paths from the CDF but also the missing parents (implicitly defined
* catalogs). */
@@ -476,7 +477,7 @@ TEST_F(AssetCatalogTest, foreach_in_tree)
}
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+ service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
std::vector<AssetCatalogPath> expected_root_items{{"character", "path"}};
AssetCatalogTree *tree = service.get_catalog_tree();
@@ -499,7 +500,7 @@ TEST_F(AssetCatalogTest, foreach_in_tree)
TEST_F(AssetCatalogTest, find_catalog_by_path)
{
TestableAssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" +
+ service.load_from_disk(asset_library_root_ + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME);
AssetCatalog *catalog;
@@ -522,7 +523,7 @@ TEST_F(AssetCatalogTest, find_catalog_by_path)
TEST_F(AssetCatalogTest, write_single_file)
{
TestableAssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" +
+ service.load_from_disk(asset_library_root_ + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME);
const CatalogFilePath save_to_path = use_temp_path() +
@@ -550,7 +551,7 @@ TEST_F(AssetCatalogTest, write_single_file)
TEST_F(AssetCatalogTest, read_write_unicode_filepath)
{
TestableAssetCatalogService service(asset_library_root_);
- const CatalogFilePath load_from_path = asset_library_root_ + "/новый/" +
+ const CatalogFilePath load_from_path = asset_library_root_ + SEP_STR + "новый" + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME;
service.load_from_disk(load_from_path);
@@ -588,8 +589,9 @@ TEST_F(AssetCatalogTest, on_blendfile_save__with_existing_cdf)
const CatalogFilePath top_level_dir = create_temp_path(); /* Has trailing slash. */
/* Create a copy of the CDF in SVN, so we can safely write to it. */
- const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt";
- const CatalogFilePath cdf_dirname = top_level_dir + "other_dir/";
+ const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR +
+ "blender_assets.cats.txt";
+ const CatalogFilePath cdf_dirname = top_level_dir + "other_dir" + SEP_STR;
const CatalogFilePath cdf_filename = cdf_dirname + AssetCatalogService::DEFAULT_CATALOG_FILENAME;
ASSERT_TRUE(BLI_dir_create_recursive(cdf_dirname.c_str()));
ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), cdf_filename.c_str()))
@@ -600,7 +602,7 @@ TEST_F(AssetCatalogTest, on_blendfile_save__with_existing_cdf)
service.load_from_disk();
const AssetCatalog *cat = service.create_catalog("some/catalog/path");
- const CatalogFilePath blendfilename = top_level_dir + "subdir/some_file.blend";
+ const CatalogFilePath blendfilename = top_level_dir + "subdir" + SEP_STR + "some_file.blend";
ASSERT_TRUE(service.write_to_disk(blendfilename));
EXPECT_EQ(cdf_filename, service.get_catalog_definition_file()->file_path);
@@ -650,7 +652,8 @@ TEST_F(AssetCatalogTest, on_blendfile_save__from_memory_into_empty_directory)
TEST_F(AssetCatalogTest, on_blendfile_save__from_memory_into_existing_cdf_and_merge)
{
const CatalogFilePath target_dir = create_temp_path(); /* Has trailing slash. */
- const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt";
+ const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR +
+ "blender_assets.cats.txt";
CatalogFilePath writable_cdf_file = target_dir + AssetCatalogService::DEFAULT_CATALOG_FILENAME;
BLI_path_slash_native(writable_cdf_file.data());
ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), writable_cdf_file.c_str()));
@@ -719,7 +722,7 @@ TEST_F(AssetCatalogTest, create_first_catalog_from_scratch)
service.write_to_disk(temp_lib_root + "phony.blend");
EXPECT_TRUE(BLI_is_dir(temp_lib_root.c_str()));
- const CatalogFilePath definition_file_path = temp_lib_root + "/" +
+ const CatalogFilePath definition_file_path = temp_lib_root + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME;
EXPECT_TRUE(BLI_is_file(definition_file_path.c_str()));
@@ -739,7 +742,7 @@ TEST_F(AssetCatalogTest, create_catalog_after_loading_file)
/* Copy the asset catalog definition files to a separate location, so that we can test without
* overwriting the test file in SVN. */
- const CatalogFilePath default_catalog_path = asset_library_root_ + "/" +
+ const CatalogFilePath default_catalog_path = asset_library_root_ + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME;
const CatalogFilePath writable_catalog_path = temp_lib_root +
AssetCatalogService::DEFAULT_CATALOG_FILENAME;
@@ -801,7 +804,7 @@ TEST_F(AssetCatalogTest, create_catalog_simple_name)
TEST_F(AssetCatalogTest, delete_catalog_leaf)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+ service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
/* Delete a leaf catalog, i.e. one that is not a parent of another catalog.
* This keeps this particular test easy. */
@@ -833,7 +836,7 @@ TEST_F(AssetCatalogTest, delete_catalog_leaf)
TEST_F(AssetCatalogTest, delete_catalog_parent_by_id)
{
TestableAssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+ service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
/* Delete a parent catalog. */
service.delete_catalog_by_id_soft(UUID_POSES_RUZENA);
@@ -847,7 +850,7 @@ TEST_F(AssetCatalogTest, delete_catalog_parent_by_id)
TEST_F(AssetCatalogTest, delete_catalog_parent_by_path)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" + "blender_assets.cats.txt");
+ service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
/* Create an extra catalog with the to-be-deleted path, and one with a child of that.
* This creates some duplicates that are bound to occur in production asset libraries as well.
@@ -887,14 +890,14 @@ TEST_F(AssetCatalogTest, delete_catalog_parent_by_path)
TEST_F(AssetCatalogTest, delete_catalog_write_to_disk)
{
TestableAssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" +
+ service.load_from_disk(asset_library_root_ + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME);
service.delete_catalog_by_id_soft(UUID_POSES_ELLIE);
const CatalogFilePath save_to_path = use_temp_path();
AssetCatalogDefinitionFile *cdf = service.get_catalog_definition_file();
- cdf->write_to_disk(save_to_path + "/" + AssetCatalogService::DEFAULT_CATALOG_FILENAME);
+ cdf->write_to_disk(save_to_path + SEP_STR + AssetCatalogService::DEFAULT_CATALOG_FILENAME);
AssetCatalogService loaded_service(save_to_path);
loaded_service.load_from_disk();
@@ -911,7 +914,7 @@ TEST_F(AssetCatalogTest, delete_catalog_write_to_disk)
TEST_F(AssetCatalogTest, update_catalog_path)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" +
+ service.load_from_disk(asset_library_root_ + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME);
const AssetCatalog *orig_cat = service.find_catalog(UUID_POSES_RUZENA);
@@ -940,7 +943,7 @@ TEST_F(AssetCatalogTest, update_catalog_path)
TEST_F(AssetCatalogTest, update_catalog_path_simple_name)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" +
+ service.load_from_disk(asset_library_root_ + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME);
service.update_catalog_path(UUID_POSES_RUZENA, "charlib/Ružena");
@@ -956,7 +959,7 @@ TEST_F(AssetCatalogTest, update_catalog_path_simple_name)
TEST_F(AssetCatalogTest, update_catalog_path_longer_than_simplename)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" +
+ service.load_from_disk(asset_library_root_ + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME);
const std::string new_path =
"this/is/a/very/long/path/that/exceeds/the/simple-name/length/of/assets";
@@ -978,7 +981,7 @@ TEST_F(AssetCatalogTest, update_catalog_path_longer_than_simplename)
TEST_F(AssetCatalogTest, update_catalog_path_add_slashes)
{
AssetCatalogService service(asset_library_root_);
- service.load_from_disk(asset_library_root_ + "/" +
+ service.load_from_disk(asset_library_root_ + SEP_STR +
AssetCatalogService::DEFAULT_CATALOG_FILENAME);
const AssetCatalog *orig_cat = service.find_catalog(UUID_POSES_RUZENA);
@@ -1019,8 +1022,10 @@ TEST_F(AssetCatalogTest, update_catalog_path_add_slashes)
TEST_F(AssetCatalogTest, merge_catalog_files)
{
const CatalogFilePath cdf_dir = create_temp_path();
- const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt";
- const CatalogFilePath modified_cdf_file = asset_library_root_ + "/modified_assets.cats.txt";
+ const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR +
+ "blender_assets.cats.txt";
+ const CatalogFilePath modified_cdf_file = asset_library_root_ + SEP_STR +
+ "modified_assets.cats.txt";
const CatalogFilePath temp_cdf_file = cdf_dir + "blender_assets.cats.txt";
ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), temp_cdf_file.c_str()));
@@ -1059,8 +1064,10 @@ TEST_F(AssetCatalogTest, merge_catalog_files)
TEST_F(AssetCatalogTest, refresh_catalogs_with_modification)
{
const CatalogFilePath cdf_dir = create_temp_path();
- const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt";
- const CatalogFilePath modified_cdf_file = asset_library_root_ + "/catalog_reload_test.cats.txt";
+ const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR +
+ "blender_assets.cats.txt";
+ const CatalogFilePath modified_cdf_file = asset_library_root_ + SEP_STR +
+ "catalog_reload_test.cats.txt";
const CatalogFilePath temp_cdf_file = cdf_dir + "blender_assets.cats.txt";
ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), temp_cdf_file.c_str()));
@@ -1131,8 +1138,9 @@ TEST_F(AssetCatalogTest, refresh_catalogs_with_modification)
TEST_F(AssetCatalogTest, backups)
{
const CatalogFilePath cdf_dir = create_temp_path();
- const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt";
- const CatalogFilePath writable_cdf_file = cdf_dir + "/blender_assets.cats.txt";
+ const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR +
+ "blender_assets.cats.txt";
+ const CatalogFilePath writable_cdf_file = cdf_dir + SEP_STR + "blender_assets.cats.txt";
ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), writable_cdf_file.c_str()));
/* Read a CDF, modify, and write it. */
diff --git a/source/blender/blenkernel/intern/asset_library_service_test.cc b/source/blender/blenkernel/intern/asset_library_service_test.cc
index de6180cb684..d105c5644de 100644
--- a/source/blender/blenkernel/intern/asset_library_service_test.cc
+++ b/source/blender/blenkernel/intern/asset_library_service_test.cc
@@ -39,7 +39,7 @@ class AssetLibraryServiceTest : public testing::Test {
if (test_files_dir.empty()) {
FAIL();
}
- asset_library_root_ = test_files_dir + "/" + "asset_library";
+ asset_library_root_ = test_files_dir + SEP_STR + "asset_library";
temp_library_path_ = "";
}
@@ -59,7 +59,7 @@ class AssetLibraryServiceTest : public testing::Test {
{
BKE_tempdir_init("");
const CatalogFilePath tempdir = BKE_tempdir_session();
- temp_library_path_ = tempdir + "test-temporary-path/";
+ temp_library_path_ = tempdir + "test-temporary-path" + SEP_STR;
return temp_library_path_;
}
@@ -168,7 +168,8 @@ TEST_F(AssetLibraryServiceTest, has_any_unsaved_catalogs)
TEST_F(AssetLibraryServiceTest, has_any_unsaved_catalogs_after_write)
{
const CatalogFilePath writable_dir = create_temp_path(); /* Has trailing slash. */
- const CatalogFilePath original_cdf_file = asset_library_root_ + "/blender_assets.cats.txt";
+ const CatalogFilePath original_cdf_file = asset_library_root_ + SEP_STR +
+ "blender_assets.cats.txt";
CatalogFilePath writable_cdf_file = writable_dir + AssetCatalogService::DEFAULT_CATALOG_FILENAME;
BLI_path_slash_native(writable_cdf_file.data());
ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), writable_cdf_file.c_str()));
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index a5096b4f9eb..f22dfc6054a 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -116,7 +116,7 @@ MemFileUndoData *BKE_memfile_undo_encode(Main *bmain, MemFileUndoData *mfu_prev)
counter = counter % U.undosteps;
BLI_snprintf(numstr, sizeof(numstr), "%d.blend", counter);
- BLI_join_dirfile(filepath, sizeof(filepath), BKE_tempdir_session(), numstr);
+ BLI_path_join(filepath, sizeof(filepath), BKE_tempdir_session(), numstr);
/* success = */ /* UNUSED */ BLO_write_file(
bmain, filepath, fileflags, &(const struct BlendFileWriteParams){0}, NULL);
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index 6546659f6cd..85a43b7c479 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -737,7 +737,7 @@ bool BKE_blendfile_userdef_write_all(ReportList *reports)
if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL))) {
bool ok_write;
- BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL);
+ BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE);
printf("Writing userprefs: '%s' ", filepath);
if (use_template_userpref) {
@@ -764,7 +764,7 @@ bool BKE_blendfile_userdef_write_all(ReportList *reports)
if (use_template_userpref) {
if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, U.app_template))) {
/* Also save app-template prefs */
- BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL);
+ BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE);
printf("Writing userprefs app-template: '%s' ", filepath);
if (BKE_blendfile_userdef_write(filepath, reports) != 0) {
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index f639d03ae0f..6bf121675bc 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -155,7 +155,7 @@ bool BKE_bpath_foreach_path_dirfile_fixed_process(BPathForeachPathData *bpath_da
char path_src[FILE_MAX];
char path_dst[FILE_MAX];
- BLI_join_dirfile(path_src, sizeof(path_src), path_dir, path_file);
+ BLI_path_join(path_src, sizeof(path_src), path_dir, path_file);
/* So that functions can access the old value. */
BLI_strncpy(path_dst, path_src, FILE_MAX);
@@ -279,7 +279,7 @@ static bool missing_files_find__recursive(const char *search_directory,
continue;
}
- BLI_join_dirfile(path, sizeof(path), search_directory, de->d_name);
+ BLI_path_join(path, sizeof(path), search_directory, de->d_name);
if (BLI_stat(path, &status) == -1) {
CLOG_WARN(&LOG, "Cannot get file status (`stat()`) of '%s'", path);
diff --git a/source/blender/blenkernel/intern/bvhutils.cc b/source/blender/blenkernel/intern/bvhutils.cc
index 58b377eecdb..afc3e525143 100644
--- a/source/blender/blenkernel/intern/bvhutils.cc
+++ b/source/blender/blenkernel/intern/bvhutils.cc
@@ -51,13 +51,13 @@ struct BVHCache {
* When the `r_locked` is filled and the tree could not be found the caches mutex will be
* locked. This mutex can be unlocked by calling `bvhcache_unlock`.
*
- * When `r_locked` is used the `mesh_eval_mutex` must contain the `Mesh_Runtime.eval_mutex`.
+ * When `r_locked` is used the `mesh_eval_mutex` must contain the `MeshRuntime.eval_mutex`.
*/
static bool bvhcache_find(BVHCache **bvh_cache_p,
BVHCacheType type,
BVHTree **r_tree,
bool *r_locked,
- ThreadMutex *mesh_eval_mutex)
+ std::mutex *mesh_eval_mutex)
{
bool do_lock = r_locked;
if (r_locked) {
@@ -69,11 +69,10 @@ static bool bvhcache_find(BVHCache **bvh_cache_p,
return false;
}
/* Lazy initialization of the bvh_cache using the `mesh_eval_mutex`. */
- BLI_mutex_lock(mesh_eval_mutex);
+ std::lock_guard lock{*mesh_eval_mutex};
if (*bvh_cache_p == nullptr) {
*bvh_cache_p = bvhcache_init();
}
- BLI_mutex_unlock(mesh_eval_mutex);
}
BVHCache *bvh_cache = *bvh_cache_p;
@@ -1222,8 +1221,7 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
const BVHCacheType bvh_cache_type,
const int tree_type)
{
- BVHCache **bvh_cache_p = (BVHCache **)&mesh->runtime.bvh_cache;
- ThreadMutex *mesh_eval_mutex = (ThreadMutex *)mesh->runtime.eval_mutex;
+ BVHCache **bvh_cache_p = (BVHCache **)&mesh->runtime->bvh_cache;
const MLoopTri *looptri = nullptr;
int looptri_len = 0;
@@ -1248,7 +1246,7 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
bool lock_started = false;
data->cached = bvhcache_find(
- bvh_cache_p, bvh_cache_type, &data->tree, &lock_started, mesh_eval_mutex);
+ bvh_cache_p, bvh_cache_type, &data->tree, &lock_started, &mesh->runtime->eval_mutex);
if (data->cached) {
BLI_assert(lock_started == false);
@@ -1352,7 +1350,7 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
const int tree_type,
const BVHCacheType bvh_cache_type,
BVHCache **bvh_cache_p,
- ThreadMutex *mesh_eval_mutex)
+ std::mutex *mesh_eval_mutex)
{
bool lock_started = false;
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 7ee6b4cdfc0..89983eb8f62 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -826,7 +826,7 @@ static void cloth_from_mesh(ClothModifierData *clmd, const Object *ob, Mesh *mes
const MLoop *mloop = BKE_mesh_loops(mesh);
const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(mesh);
const uint mvert_num = mesh->totvert;
- const uint looptri_num = mesh->runtime.looptris.len;
+ const uint looptri_num = BKE_mesh_runtime_looptri_len(mesh);
/* Allocate our vertices. */
clmd->clothObject->mvert_num = mvert_num;
diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc
index be99a8ee87b..6f2390fc28f 100644
--- a/source/blender/blenkernel/intern/customdata.cc
+++ b/source/blender/blenkernel/intern/customdata.cc
@@ -2382,16 +2382,21 @@ static bool attribute_stored_in_bmesh_flag(const StringRef name)
"material_index");
}
-static CustomData shallow_copy_remove_non_bmesh_attributes(const CustomData &src)
+CustomData CustomData_shallow_copy_remove_non_bmesh_attributes(const CustomData *src,
+ const eCustomDataMask mask)
{
Vector<CustomDataLayer> dst_layers;
- for (const CustomDataLayer &layer : Span<CustomDataLayer>{src.layers, src.totlayer}) {
- if (!attribute_stored_in_bmesh_flag(layer.name)) {
- dst_layers.append(layer);
+ for (const CustomDataLayer &layer : Span<CustomDataLayer>{src->layers, src->totlayer}) {
+ if (attribute_stored_in_bmesh_flag(layer.name)) {
+ continue;
+ }
+ if (!(mask & CD_TYPE_AS_MASK(layer.type))) {
+ continue;
}
+ dst_layers.append(layer);
}
- CustomData dst = src;
+ CustomData dst = *src;
dst.layers = static_cast<CustomDataLayer *>(
MEM_calloc_arrayN(dst_layers.size(), sizeof(CustomDataLayer), __func__));
dst.totlayer = dst_layers.size();
@@ -2402,18 +2407,6 @@ static CustomData shallow_copy_remove_non_bmesh_attributes(const CustomData &src
return dst;
}
-bool CustomData_merge_mesh_to_bmesh(const CustomData *source,
- CustomData *dest,
- const eCustomDataMask mask,
- const eCDAllocType alloctype,
- const int totelem)
-{
- CustomData source_copy = shallow_copy_remove_non_bmesh_attributes(*source);
- const bool result = CustomData_merge(&source_copy, dest, mask, alloctype, totelem);
- MEM_SAFE_FREE(source_copy.layers);
- return result;
-}
-
void CustomData_realloc(CustomData *data, const int old_size, const int new_size)
{
BLI_assert(new_size >= 0);
@@ -2463,17 +2456,6 @@ void CustomData_copy(const CustomData *source,
CustomData_merge(source, dest, mask, alloctype, totelem);
}
-void CustomData_copy_mesh_to_bmesh(const CustomData *source,
- CustomData *dest,
- const eCustomDataMask mask,
- const eCDAllocType alloctype,
- const int totelem)
-{
- CustomData source_copy = shallow_copy_remove_non_bmesh_attributes(*source);
- CustomData_copy(&source_copy, dest, mask, alloctype, totelem);
- MEM_SAFE_FREE(source_copy.layers);
-}
-
static void customData_free_layer__internal(CustomDataLayer *layer, const int totelem)
{
const LayerTypeInfo *typeInfo;
@@ -3697,7 +3679,7 @@ bool CustomData_bmesh_merge(const CustomData *source,
destold.layers = static_cast<CustomDataLayer *>(MEM_dupallocN(destold.layers));
}
- if (CustomData_merge_mesh_to_bmesh(source, dest, mask, alloctype, 0) == false) {
+ if (CustomData_merge(source, dest, mask, alloctype, 0) == false) {
if (destold.layers) {
MEM_freeN(destold.layers);
}
diff --git a/source/blender/blenkernel/intern/editmesh.cc b/source/blender/blenkernel/intern/editmesh.cc
index 2ed5ec7469f..b586b4110f2 100644
--- a/source/blender/blenkernel/intern/editmesh.cc
+++ b/source/blender/blenkernel/intern/editmesh.cc
@@ -240,12 +240,12 @@ const float (*BKE_editmesh_vert_coords_when_deformed(Depsgraph *depsgraph,
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object_eval);
- if ((me->runtime.edit_data != nullptr) && (me->runtime.edit_data->vertexCos != nullptr)) {
+ if ((me->runtime->edit_data != nullptr) && (me->runtime->edit_data->vertexCos != nullptr)) {
/* Deformed, and we have deformed coords already. */
- coords = me->runtime.edit_data->vertexCos;
+ coords = me->runtime->edit_data->vertexCos;
}
else if ((editmesh_eval_final != nullptr) &&
- (editmesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH)) {
+ (editmesh_eval_final->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH)) {
/* If this is an edit-mesh type, leave nullptr as we can use the vertex coords. */
}
else {
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index 0a39207184a..5470231cd07 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -327,17 +327,17 @@ void BKE_fluid_cache_free(FluidDomainSettings *fds, Object *ob, int cache_map)
if (cache_map & FLUID_DOMAIN_OUTDATED_DATA) {
flags &= ~(FLUID_DOMAIN_BAKING_DATA | FLUID_DOMAIN_BAKED_DATA | FLUID_DOMAIN_OUTDATED_DATA);
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_CONFIG);
BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
}
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_DATA, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_DATA);
BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
}
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT);
BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
@@ -346,7 +346,7 @@ void BKE_fluid_cache_free(FluidDomainSettings *fds, Object *ob, int cache_map)
}
if (cache_map & FLUID_DOMAIN_OUTDATED_NOISE) {
flags &= ~(FLUID_DOMAIN_BAKING_NOISE | FLUID_DOMAIN_BAKED_NOISE | FLUID_DOMAIN_OUTDATED_NOISE);
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_NOISE, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_NOISE);
BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
@@ -355,7 +355,7 @@ void BKE_fluid_cache_free(FluidDomainSettings *fds, Object *ob, int cache_map)
}
if (cache_map & FLUID_DOMAIN_OUTDATED_MESH) {
flags &= ~(FLUID_DOMAIN_BAKING_MESH | FLUID_DOMAIN_BAKED_MESH | FLUID_DOMAIN_OUTDATED_MESH);
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_MESH, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_MESH);
BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
@@ -365,8 +365,7 @@ void BKE_fluid_cache_free(FluidDomainSettings *fds, Object *ob, int cache_map)
if (cache_map & FLUID_DOMAIN_OUTDATED_PARTICLES) {
flags &= ~(FLUID_DOMAIN_BAKING_PARTICLES | FLUID_DOMAIN_BAKED_PARTICLES |
FLUID_DOMAIN_OUTDATED_PARTICLES);
- BLI_path_join(
- temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES);
BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
@@ -375,7 +374,7 @@ void BKE_fluid_cache_free(FluidDomainSettings *fds, Object *ob, int cache_map)
}
if (cache_map & FLUID_DOMAIN_OUTDATED_GUIDE) {
flags &= ~(FLUID_DOMAIN_BAKING_GUIDE | FLUID_DOMAIN_BAKED_GUIDE | FLUID_DOMAIN_OUTDATED_GUIDE);
- BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_GUIDE, NULL);
+ BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_GUIDE);
BLI_path_abs(temp_dir, relbase);
if (BLI_exists(temp_dir)) {
BLI_delete(temp_dir, true, true);
diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc
index 0b5f7cbf902..be1d9524509 100644
--- a/source/blender/blenkernel/intern/geometry_component_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_component_instances.cc
@@ -16,6 +16,7 @@
#include "BKE_attribute_math.hh"
#include "BKE_geometry_set.hh"
#include "BKE_geometry_set_instances.hh"
+#include "BKE_instances.hh"
#include "attribute_access_intern.hh"
@@ -29,8 +30,8 @@ using blender::MutableSpan;
using blender::Set;
using blender::Span;
using blender::VectorSet;
-
-BLI_CPP_TYPE_MAKE(InstanceReference, InstanceReference, CPPTypeFlags::None)
+using blender::bke::InstanceReference;
+using blender::bke::Instances;
/* -------------------------------------------------------------------- */
/** \name Geometry Component Implementation
@@ -40,339 +41,76 @@ InstancesComponent::InstancesComponent() : GeometryComponent(GEO_COMPONENT_TYPE_
{
}
-GeometryComponent *InstancesComponent::copy() const
-{
- InstancesComponent *new_component = new InstancesComponent();
- new_component->instance_reference_handles_ = instance_reference_handles_;
- new_component->instance_transforms_ = instance_transforms_;
- new_component->references_ = references_;
- new_component->attributes_ = attributes_;
- return new_component;
-}
-
-void InstancesComponent::reserve(int min_capacity)
+InstancesComponent::~InstancesComponent()
{
- instance_reference_handles_.reserve(min_capacity);
- instance_transforms_.reserve(min_capacity);
- attributes_.reallocate(min_capacity);
+ this->clear();
}
-void InstancesComponent::resize(int capacity)
+GeometryComponent *InstancesComponent::copy() const
{
- instance_reference_handles_.resize(capacity);
- instance_transforms_.resize(capacity);
- attributes_.reallocate(capacity);
+ InstancesComponent *new_component = new InstancesComponent();
+ if (instances_ != nullptr) {
+ new_component->instances_ = new Instances(*instances_);
+ new_component->ownership_ = GeometryOwnershipType::Owned;
+ }
+ return new_component;
}
void InstancesComponent::clear()
{
- instance_reference_handles_.clear();
- instance_transforms_.clear();
- attributes_.clear();
- references_.clear();
-}
-
-void InstancesComponent::add_instance(const int instance_handle, const float4x4 &transform)
-{
- BLI_assert(instance_handle >= 0);
- BLI_assert(instance_handle < references_.size());
- instance_reference_handles_.append(instance_handle);
- instance_transforms_.append(transform);
- attributes_.reallocate(this->instances_num());
-}
-
-blender::Span<int> InstancesComponent::instance_reference_handles() const
-{
- return instance_reference_handles_;
-}
-
-blender::MutableSpan<int> InstancesComponent::instance_reference_handles()
-{
- return instance_reference_handles_;
-}
-
-blender::MutableSpan<blender::float4x4> InstancesComponent::instance_transforms()
-{
- return instance_transforms_;
-}
-blender::Span<blender::float4x4> InstancesComponent::instance_transforms() const
-{
- return instance_transforms_;
-}
-
-GeometrySet &InstancesComponent::geometry_set_from_reference(const int reference_index)
-{
- /* If this assert fails, it means #ensure_geometry_instances must be called first or that the
- * reference can't be converted to a geometry set. */
- BLI_assert(references_[reference_index].type() == InstanceReference::Type::GeometrySet);
-
- /* The const cast is okay because the instance's hash in the set
- * is not changed by adjusting the data inside the geometry set. */
- return const_cast<GeometrySet &>(references_[reference_index].geometry_set());
-}
-
-int InstancesComponent::add_reference(const InstanceReference &reference)
-{
- return references_.index_of_or_add_as(reference);
-}
-
-blender::Span<InstanceReference> InstancesComponent::references() const
-{
- return references_;
-}
-
-template<typename T>
-static void copy_data_based_on_mask(Span<T> src, MutableSpan<T> dst, IndexMask mask)
-{
- BLI_assert(src.data() != dst.data());
- using namespace blender;
- threading::parallel_for(mask.index_range(), 1024, [&](IndexRange range) {
- for (const int i : range) {
- dst[i] = src[mask[i]];
- }
- });
-}
-
-void InstancesComponent::remove_instances(const IndexMask mask)
-{
- using namespace blender;
- if (mask.is_range() && mask.as_range().start() == 0) {
- /* Deleting from the end of the array can be much faster since no data has to be shifted. */
- this->resize(mask.size());
- this->remove_unused_references();
- return;
+ BLI_assert(this->is_mutable());
+ if (ownership_ == GeometryOwnershipType::Owned) {
+ delete instances_;
}
-
- Vector<int> new_handles(mask.size());
- copy_data_based_on_mask<int>(this->instance_reference_handles(), new_handles, mask);
- instance_reference_handles_ = std::move(new_handles);
- Vector<float4x4> new_transforms(mask.size());
- copy_data_based_on_mask<float4x4>(this->instance_transforms(), new_transforms, mask);
- instance_transforms_ = std::move(new_transforms);
-
- const bke::CustomDataAttributes &src_attributes = attributes_;
-
- bke::CustomDataAttributes dst_attributes;
- dst_attributes.reallocate(mask.size());
-
- src_attributes.foreach_attribute(
- [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData &meta_data) {
- if (!id.should_be_kept()) {
- return true;
- }
-
- GSpan src = *src_attributes.get_for_read(id);
- dst_attributes.create(id, meta_data.data_type);
- GMutableSpan dst = *dst_attributes.get_for_write(id);
-
- attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
- using T = decltype(dummy);
- copy_data_based_on_mask<T>(src.typed<T>(), dst.typed<T>(), mask);
- });
- return true;
- },
- ATTR_DOMAIN_INSTANCE);
-
- attributes_ = std::move(dst_attributes);
- this->remove_unused_references();
+ instances_ = nullptr;
}
-void InstancesComponent::remove_unused_references()
+bool InstancesComponent::is_empty() const
{
- using namespace blender;
- using namespace blender::bke;
-
- const int tot_instances = this->instances_num();
- const int tot_references_before = references_.size();
-
- if (tot_instances == 0) {
- /* If there are no instances, no reference is needed. */
- references_.clear();
- return;
- }
- if (tot_references_before == 1) {
- /* There is only one reference and at least one instance. So the only existing reference is
- * used. Nothing to do here. */
- return;
- }
-
- Array<bool> usage_by_handle(tot_references_before, false);
- std::mutex mutex;
-
- /* Loop over all instances to see which references are used. */
- threading::parallel_for(IndexRange(tot_instances), 1000, [&](IndexRange range) {
- /* Use local counter to avoid lock contention. */
- Array<bool> local_usage_by_handle(tot_references_before, false);
-
- for (const int i : range) {
- const int handle = instance_reference_handles_[i];
- BLI_assert(handle >= 0 && handle < tot_references_before);
- local_usage_by_handle[handle] = true;
- }
-
- std::lock_guard lock{mutex};
- for (const int i : IndexRange(tot_references_before)) {
- usage_by_handle[i] |= local_usage_by_handle[i];
- }
- });
-
- if (!usage_by_handle.as_span().contains(false)) {
- /* All references are used. */
- return;
- }
-
- /* Create new references and a mapping for the handles. */
- Vector<int> handle_mapping;
- VectorSet<InstanceReference> new_references;
- int next_new_handle = 0;
- bool handles_have_to_be_updated = false;
- for (const int old_handle : IndexRange(tot_references_before)) {
- if (!usage_by_handle[old_handle]) {
- /* Add some dummy value. It won't be read again. */
- handle_mapping.append(-1);
- }
- else {
- const InstanceReference &reference = references_[old_handle];
- handle_mapping.append(next_new_handle);
- new_references.add_new(reference);
- if (old_handle != next_new_handle) {
- handles_have_to_be_updated = true;
- }
- next_new_handle++;
+ if (instances_ != nullptr) {
+ if (instances_->instances_num() > 0) {
+ return false;
}
}
- references_ = new_references;
-
- if (!handles_have_to_be_updated) {
- /* All remaining handles are the same as before, so they don't have to be updated. This happens
- * when unused handles are only at the end. */
- return;
- }
-
- /* Update handles of instances. */
- threading::parallel_for(IndexRange(tot_instances), 1000, [&](IndexRange range) {
- for (const int i : range) {
- instance_reference_handles_[i] = handle_mapping[instance_reference_handles_[i]];
- }
- });
-}
-
-int InstancesComponent::instances_num() const
-{
- return instance_transforms_.size();
-}
-
-int InstancesComponent::references_num() const
-{
- return references_.size();
-}
-
-bool InstancesComponent::is_empty() const
-{
- return this->instance_reference_handles_.size() == 0;
+ return true;
}
bool InstancesComponent::owns_direct_data() const
{
- for (const InstanceReference &reference : references_) {
- if (!reference.owns_direct_data()) {
- return false;
- }
+ if (instances_ != nullptr) {
+ return instances_->owns_direct_data();
}
return true;
}
void InstancesComponent::ensure_owns_direct_data()
{
- BLI_assert(this->is_mutable());
- for (const InstanceReference &const_reference : references_) {
- /* Const cast is fine because we are not changing anything that would change the hash of the
- * reference. */
- InstanceReference &reference = const_cast<InstanceReference &>(const_reference);
- reference.ensure_owns_direct_data();
+ if (instances_ != nullptr) {
+ instances_->ensure_owns_direct_data();
}
}
-static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids)
+const blender::bke::Instances *InstancesComponent::get_for_read() const
{
- using namespace blender;
- Array<int> unique_ids(original_ids.size());
-
- Set<int> used_unique_ids;
- used_unique_ids.reserve(original_ids.size());
- Vector<int> instances_with_id_collision;
- for (const int instance_index : original_ids.index_range()) {
- const int original_id = original_ids[instance_index];
- if (used_unique_ids.add(original_id)) {
- /* The original id has not been used by another instance yet. */
- unique_ids[instance_index] = original_id;
- }
- else {
- /* The original id of this instance collided with a previous instance, it needs to be looked
- * at again in a second pass. Don't generate a new random id here, because this might collide
- * with other existing ids. */
- instances_with_id_collision.append(instance_index);
- }
- }
-
- Map<int, RandomNumberGenerator> generator_by_original_id;
- for (const int instance_index : instances_with_id_collision) {
- const int original_id = original_ids[instance_index];
- RandomNumberGenerator &rng = generator_by_original_id.lookup_or_add_cb(original_id, [&]() {
- RandomNumberGenerator rng;
- rng.seed_random(original_id);
- return rng;
- });
-
- const int max_iteration = 100;
- for (int iteration = 0;; iteration++) {
- /* Try generating random numbers until an unused one has been found. */
- const int random_id = rng.get_int32();
- if (used_unique_ids.add(random_id)) {
- /* This random id is not used by another instance. */
- unique_ids[instance_index] = random_id;
- break;
- }
- if (iteration == max_iteration) {
- /* It seems to be very unlikely that we ever run into this case (assuming there are less
- * than 2^30 instances). However, if that happens, it's better to use an id that is not
- * unique than to be stuck in an infinite loop. */
- unique_ids[instance_index] = original_id;
- break;
- }
- }
- }
-
- return unique_ids;
+ return instances_;
}
-blender::Span<int> InstancesComponent::almost_unique_ids() const
+blender::bke::Instances *InstancesComponent::get_for_write()
{
- std::lock_guard lock(almost_unique_ids_mutex_);
- std::optional<GSpan> instance_ids_gspan = attributes_.get_for_read("id");
- if (instance_ids_gspan) {
- Span<int> instance_ids = instance_ids_gspan->typed<int>();
- if (almost_unique_ids_.size() != instance_ids.size()) {
- almost_unique_ids_ = generate_unique_instance_ids(instance_ids);
- }
- }
- else {
- almost_unique_ids_.reinitialize(this->instances_num());
- for (const int i : almost_unique_ids_.index_range()) {
- almost_unique_ids_[i] = i;
- }
+ BLI_assert(this->is_mutable());
+ if (ownership_ == GeometryOwnershipType::ReadOnly) {
+ instances_ = new Instances(*instances_);
+ ownership_ = GeometryOwnershipType::Owned;
}
- return almost_unique_ids_;
+ return instances_;
}
-blender::bke::CustomDataAttributes &InstancesComponent::instance_attributes()
+void InstancesComponent::replace(Instances *instances, GeometryOwnershipType ownership)
{
- return this->attributes_;
-}
-
-const blender::bke::CustomDataAttributes &InstancesComponent::instance_attributes() const
-{
- return this->attributes_;
+ BLI_assert(this->is_mutable());
+ this->clear();
+ instances_ = instances;
+ ownership_ = ownership;
}
namespace blender::bke {
@@ -397,16 +135,21 @@ class InstancePositionAttributeProvider final : public BuiltinAttributeProvider
GVArray try_get_for_read(const void *owner) const final
{
- const InstancesComponent &instances_component = *static_cast<const InstancesComponent *>(
- owner);
- Span<float4x4> transforms = instances_component.instance_transforms();
+ const Instances *instances = static_cast<const Instances *>(owner);
+ if (instances == nullptr) {
+ return {};
+ }
+ Span<float4x4> transforms = instances->transforms();
return VArray<float3>::ForDerivedSpan<float4x4, get_transform_position>(transforms);
}
GAttributeWriter try_get_for_write(void *owner) const final
{
- InstancesComponent &instances_component = *static_cast<InstancesComponent *>(owner);
- MutableSpan<float4x4> transforms = instances_component.instance_transforms();
+ Instances *instances = static_cast<Instances *>(owner);
+ if (instances == nullptr) {
+ return {};
+ }
+ MutableSpan<float4x4> transforms = instances->transforms();
return {VMutableArray<float3>::ForDerivedSpan<float4x4,
get_transform_position,
set_transform_position>(transforms),
@@ -434,16 +177,16 @@ static ComponentAttributeProviders create_attribute_providers_for_instances()
static InstancePositionAttributeProvider position;
static CustomDataAccessInfo instance_custom_data_access = {
[](void *owner) -> CustomData * {
- InstancesComponent &inst = *static_cast<InstancesComponent *>(owner);
- return &inst.instance_attributes().data;
+ Instances *instances = static_cast<Instances *>(owner);
+ return &instances->custom_data_attributes().data;
},
[](const void *owner) -> const CustomData * {
- const InstancesComponent &inst = *static_cast<const InstancesComponent *>(owner);
- return &inst.instance_attributes().data;
+ const Instances *instances = static_cast<const Instances *>(owner);
+ return &instances->custom_data_attributes().data;
},
[](const void *owner) -> int {
- const InstancesComponent &inst = *static_cast<const InstancesComponent *>(owner);
- return inst.instances_num();
+ const Instances *instances = static_cast<const Instances *>(owner);
+ return instances->instances_num();
}};
/**
@@ -479,10 +222,10 @@ static AttributeAccessorFunctions get_instances_accessor_functions()
if (owner == nullptr) {
return 0;
}
- const InstancesComponent &instances = *static_cast<const InstancesComponent *>(owner);
+ const Instances *instances = static_cast<const Instances *>(owner);
switch (domain) {
case ATTR_DOMAIN_INSTANCE:
- return instances.instances_num();
+ return instances->instances_num();
default:
return 0;
}
@@ -508,18 +251,30 @@ static const AttributeAccessorFunctions &get_instances_accessor_functions_ref()
return fn;
}
+blender::bke::AttributeAccessor Instances::attributes() const
+{
+ return blender::bke::AttributeAccessor(this,
+ blender::bke::get_instances_accessor_functions_ref());
+}
+
+blender::bke::MutableAttributeAccessor Instances::attributes_for_write()
+{
+ return blender::bke::MutableAttributeAccessor(
+ this, blender::bke::get_instances_accessor_functions_ref());
+}
+
} // namespace blender::bke
std::optional<blender::bke::AttributeAccessor> InstancesComponent::attributes() const
{
- return blender::bke::AttributeAccessor(this,
+ return blender::bke::AttributeAccessor(instances_,
blender::bke::get_instances_accessor_functions_ref());
}
std::optional<blender::bke::MutableAttributeAccessor> InstancesComponent::attributes_for_write()
{
return blender::bke::MutableAttributeAccessor(
- this, blender::bke::get_instances_accessor_functions_ref());
+ instances_, blender::bke::get_instances_accessor_functions_ref());
}
/** \} */
diff --git a/source/blender/blenkernel/intern/geometry_fields.cc b/source/blender/blenkernel/intern/geometry_fields.cc
index b492af4af77..82ffda57398 100644
--- a/source/blender/blenkernel/intern/geometry_fields.cc
+++ b/source/blender/blenkernel/intern/geometry_fields.cc
@@ -4,6 +4,7 @@
#include "BKE_curves.hh"
#include "BKE_geometry_fields.hh"
#include "BKE_geometry_set.hh"
+#include "BKE_instances.hh"
#include "BKE_mesh.h"
#include "BKE_pointcloud.h"
#include "BKE_type_conversions.hh"
@@ -64,7 +65,7 @@ GeometryFieldContext::GeometryFieldContext(const GeometryComponent &component,
case GEO_COMPONENT_TYPE_INSTANCES: {
const InstancesComponent &instances_component = static_cast<const InstancesComponent &>(
component);
- geometry_ = &instances_component;
+ geometry_ = instances_component.get_for_read();
break;
}
case GEO_COMPONENT_TYPE_VOLUME:
@@ -86,7 +87,7 @@ GeometryFieldContext::GeometryFieldContext(const PointCloud &points)
: geometry_(&points), type_(GEO_COMPONENT_TYPE_POINT_CLOUD), domain_(ATTR_DOMAIN_POINT)
{
}
-GeometryFieldContext::GeometryFieldContext(const InstancesComponent &instances)
+GeometryFieldContext::GeometryFieldContext(const Instances &instances)
: geometry_(&instances), type_(GEO_COMPONENT_TYPE_INSTANCES), domain_(ATTR_DOMAIN_INSTANCE)
{
}
@@ -102,7 +103,7 @@ std::optional<AttributeAccessor> GeometryFieldContext::attributes() const
if (const PointCloud *pointcloud = this->pointcloud()) {
return pointcloud->attributes();
}
- if (const InstancesComponent *instances = this->instances()) {
+ if (const Instances *instances = this->instances()) {
return instances->attributes();
}
return {};
@@ -124,11 +125,10 @@ const PointCloud *GeometryFieldContext::pointcloud() const
static_cast<const PointCloud *>(geometry_) :
nullptr;
}
-const InstancesComponent *GeometryFieldContext::instances() const
+const Instances *GeometryFieldContext::instances() const
{
- return this->type() == GEO_COMPONENT_TYPE_INSTANCES ?
- static_cast<const InstancesComponent *>(geometry_) :
- nullptr;
+ return this->type() == GEO_COMPONENT_TYPE_INSTANCES ? static_cast<const Instances *>(geometry_) :
+ nullptr;
}
GVArray GeometryFieldInput::get_varray_for_context(const fn::FieldContext &context,
@@ -230,7 +230,7 @@ GVArray InstancesFieldInput::get_varray_for_context(const fn::FieldContext &cont
{
if (const GeometryFieldContext *geometry_context = dynamic_cast<const GeometryFieldContext *>(
&context)) {
- if (const InstancesComponent *instances = geometry_context->instances()) {
+ if (const Instances *instances = geometry_context->instances()) {
return this->get_varray_for_context(*instances, mask);
}
}
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index 46ff8141504..90568a8a080 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -9,6 +9,7 @@
#include "BKE_attribute.h"
#include "BKE_curves.hh"
#include "BKE_geometry_set.hh"
+#include "BKE_instances.hh"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
#include "BKE_mesh_wrapper.h"
@@ -31,6 +32,8 @@ using blender::MutableSpan;
using blender::Span;
using blender::StringRef;
using blender::Vector;
+using blender::bke::InstanceReference;
+using blender::bke::Instances;
/* -------------------------------------------------------------------- */
/** \name Geometry Component
@@ -256,8 +259,7 @@ std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set)
parts.append(std::to_string(BKE_volume_num_grids(volume)) + " volume grids");
}
if (geometry_set.has_instances()) {
- parts.append(std::to_string(
- geometry_set.get_component_for_read<InstancesComponent>()->instances_num()) +
+ parts.append(std::to_string(geometry_set.get_instances_for_read()->instances_num()) +
" instances");
}
if (geometry_set.get_curve_edit_hints_for_read()) {
@@ -338,6 +340,12 @@ const Curves *GeometrySet::get_curves_for_read() const
return (component == nullptr) ? nullptr : component->get_for_read();
}
+const Instances *GeometrySet::get_instances_for_read() const
+{
+ const InstancesComponent *component = this->get_component_for_read<InstancesComponent>();
+ return (component == nullptr) ? nullptr : component->get_for_read();
+}
+
const blender::bke::CurvesEditHints *GeometrySet::get_curve_edit_hints_for_read() const
{
const GeometryComponentEditData *component =
@@ -354,7 +362,8 @@ bool GeometrySet::has_pointcloud() const
bool GeometrySet::has_instances() const
{
const InstancesComponent *component = this->get_component_for_read<InstancesComponent>();
- return component != nullptr && component->instances_num() >= 1;
+ return component != nullptr && component->get_for_read() != nullptr &&
+ component->get_for_read()->instances_num() >= 1;
}
bool GeometrySet::has_volume() const
@@ -428,6 +437,14 @@ GeometrySet GeometrySet::create_with_curves(Curves *curves, GeometryOwnershipTyp
return geometry_set;
}
+GeometrySet GeometrySet::create_with_instances(Instances *instances,
+ GeometryOwnershipType ownership)
+{
+ GeometrySet geometry_set;
+ geometry_set.replace_instances(instances, ownership);
+ return geometry_set;
+}
+
void GeometrySet::replace_mesh(Mesh *mesh, GeometryOwnershipType ownership)
{
if (mesh == nullptr) {
@@ -456,6 +473,20 @@ void GeometrySet::replace_curves(Curves *curves, GeometryOwnershipType ownership
component.replace(curves, ownership);
}
+void GeometrySet::replace_instances(Instances *instances, GeometryOwnershipType ownership)
+{
+ if (instances == nullptr) {
+ this->remove<InstancesComponent>();
+ return;
+ }
+ if (instances == this->get_instances_for_read()) {
+ return;
+ }
+ this->remove<InstancesComponent>();
+ InstancesComponent &component = this->get_component_for_write<InstancesComponent>();
+ component.replace(instances, ownership);
+}
+
void GeometrySet::replace_pointcloud(PointCloud *pointcloud, GeometryOwnershipType ownership)
{
if (pointcloud == nullptr) {
@@ -508,6 +539,12 @@ Curves *GeometrySet::get_curves_for_write()
return component == nullptr ? nullptr : component->get_for_write();
}
+Instances *GeometrySet::get_instances_for_write()
+{
+ InstancesComponent *component = this->get_component_ptr<InstancesComponent>();
+ return component == nullptr ? nullptr : component->get_for_write();
+}
+
blender::bke::CurvesEditHints *GeometrySet::get_curve_edit_hints_for_write()
{
if (!this->has<GeometryComponentEditData>()) {
@@ -539,7 +576,7 @@ void GeometrySet::attribute_foreach(const Span<GeometryComponentType> component_
}
}
if (include_instances && this->has_instances()) {
- const InstancesComponent &instances = *this->get_component_for_read<InstancesComponent>();
+ const Instances &instances = *this->get_instances_for_read();
instances.foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) {
instance_geometry_set.attribute_foreach(component_types, include_instances, callback);
});
@@ -611,7 +648,7 @@ static void gather_component_types_recursive(const GeometrySet &geometry_set,
if (!include_instances) {
return;
}
- const InstancesComponent *instances = geometry_set.get_component_for_read<InstancesComponent>();
+ const blender::bke::Instances *instances = geometry_set.get_instances_for_read();
if (instances == nullptr) {
return;
}
@@ -638,12 +675,11 @@ static void gather_mutable_geometry_sets(GeometrySet &geometry_set,
}
/* In the future this can be improved by deduplicating instance references across different
* instances. */
- InstancesComponent &instances_component =
- geometry_set.get_component_for_write<InstancesComponent>();
- instances_component.ensure_geometry_instances();
- for (const int handle : instances_component.references().index_range()) {
- if (instances_component.references()[handle].type() == InstanceReference::Type::GeometrySet) {
- GeometrySet &instance_geometry = instances_component.geometry_set_from_reference(handle);
+ Instances &instances = *geometry_set.get_instances_for_write();
+ instances.ensure_geometry_instances();
+ for (const int handle : instances.references().index_range()) {
+ if (instances.references()[handle].type() == InstanceReference::Type::GeometrySet) {
+ GeometrySet &instance_geometry = instances.geometry_set_from_reference(handle);
gather_mutable_geometry_sets(instance_geometry, r_geometry_sets);
}
}
diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc
index 0ae49a586f1..e078991187d 100644
--- a/source/blender/blenkernel/intern/geometry_set_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_set_instances.cc
@@ -2,6 +2,7 @@
#include "BKE_collection.h"
#include "BKE_geometry_set_instances.hh"
+#include "BKE_instances.hh"
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_mesh_wrapper.h"
@@ -62,12 +63,11 @@ GeometrySet object_get_evaluated_geometry_set(const Object &object)
return geometry_set;
}
if (object.type == OB_EMPTY && object.instance_collection != nullptr) {
- GeometrySet geometry_set;
Collection &collection = *object.instance_collection;
- InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
- const int handle = instances.add_reference(collection);
- instances.add_instance(handle, float4x4::identity());
- return geometry_set;
+ std::unique_ptr<Instances> instances = std::make_unique<Instances>();
+ const int handle = instances->add_reference(collection);
+ instances->add_instance(handle, float4x4::identity());
+ return GeometrySet::create_with_instances(instances.release());
}
/* Return by value since there is not always an existing geometry set owned elsewhere to use. */
@@ -115,12 +115,11 @@ static void geometry_set_collect_recursive(const GeometrySet &geometry_set,
r_sets.append({geometry_set, {transform}});
if (geometry_set.has_instances()) {
- const InstancesComponent &instances_component =
- *geometry_set.get_component_for_read<InstancesComponent>();
+ const Instances &instances = *geometry_set.get_instances_for_read();
- Span<float4x4> transforms = instances_component.instance_transforms();
- Span<int> handles = instances_component.instance_reference_handles();
- Span<InstanceReference> references = instances_component.references();
+ Span<float4x4> transforms = instances.transforms();
+ Span<int> handles = instances.reference_handles();
+ Span<InstanceReference> references = instances.references();
for (const int i : transforms.index_range()) {
const InstanceReference &reference = references[handles[i]];
const float4x4 instance_transform = transform * transforms[i];
@@ -156,9 +155,7 @@ void geometry_set_gather_instances(const GeometrySet &geometry_set,
geometry_set_collect_recursive(geometry_set, float4x4::identity(), r_instance_groups);
}
-} // namespace blender::bke
-
-void InstancesComponent::foreach_referenced_geometry(
+void Instances::foreach_referenced_geometry(
blender::FunctionRef<void(const GeometrySet &geometry_set)> callback) const
{
using namespace blender::bke;
@@ -191,7 +188,7 @@ void InstancesComponent::foreach_referenced_geometry(
}
}
-void InstancesComponent::ensure_geometry_instances()
+void Instances::ensure_geometry_instances()
{
using namespace blender;
using namespace blender::bke;
@@ -211,9 +208,7 @@ void InstancesComponent::ensure_geometry_instances()
const Object &object = reference.object();
GeometrySet object_geometry_set = object_get_evaluated_geometry_set(object);
if (object_geometry_set.has_instances()) {
- InstancesComponent &component =
- object_geometry_set.get_component_for_write<InstancesComponent>();
- component.ensure_geometry_instances();
+ object_geometry_set.get_instances_for_write()->ensure_geometry_instances();
}
new_references.add_new(std::move(object_geometry_set));
break;
@@ -221,22 +216,22 @@ void InstancesComponent::ensure_geometry_instances()
case InstanceReference::Type::Collection: {
/* Create a new reference that contains a geometry set that contains all objects from the
* collection as instances. */
- GeometrySet collection_geometry_set;
- InstancesComponent &component =
- collection_geometry_set.get_component_for_write<InstancesComponent>();
+ std::unique_ptr<Instances> instances = std::make_unique<Instances>();
Collection &collection = reference.collection();
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (&collection, object) {
- const int handle = component.add_reference(*object);
- component.add_instance(handle, object->obmat);
- float4x4 &transform = component.instance_transforms().last();
+ const int handle = instances->add_reference(*object);
+ instances->add_instance(handle, object->obmat);
+ float4x4 &transform = instances->transforms().last();
sub_v3_v3(transform.values[3], collection.instance_offset);
}
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
- component.ensure_geometry_instances();
- new_references.add_new(std::move(collection_geometry_set));
+ instances->ensure_geometry_instances();
+ new_references.add_new(GeometrySet::create_with_instances(instances.release()));
break;
}
}
}
references_ = std::move(new_references);
}
+
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc
index 409eb0067b5..51d8f02616f 100644
--- a/source/blender/blenkernel/intern/image.cc
+++ b/source/blender/blenkernel/intern/image.cc
@@ -297,7 +297,7 @@ static void image_foreach_path(ID *id, BPathForeachPathData *bpath_data)
/* Put the filepath back together using the new directory and the original file name. */
char new_dir[FILE_MAXDIR];
BLI_split_dir_part(temp_path, new_dir, sizeof(new_dir));
- BLI_join_dirfile(ima->filepath, sizeof(ima->filepath), new_dir, orig_file);
+ BLI_path_join(ima->filepath, sizeof(ima->filepath), new_dir, orig_file);
}
}
else {
@@ -3331,7 +3331,7 @@ bool BKE_image_get_tile_info(char *filepath, ListBase *tiles, int *r_tile_start,
MEM_SAFE_FREE(udim_pattern);
if (all_valid_udim && min_udim <= IMA_UDIM_MAX) {
- BLI_join_dirfile(filepath, FILE_MAX, dirname, filename);
+ BLI_path_join(filepath, FILE_MAX, dirname, filename);
*r_tile_start = min_udim;
*r_tile_range = max_udim - min_udim + 1;
diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc
index e227f9cba5e..4e47e71fb2b 100644
--- a/source/blender/blenkernel/intern/image_save.cc
+++ b/source/blender/blenkernel/intern/image_save.cc
@@ -175,12 +175,12 @@ bool BKE_image_save_options_init(ImageSaveOptions *opts,
BLI_strncpy(opts->filepath, G.ima, sizeof(opts->filepath));
}
else {
- BLI_path_join(opts->filepath, sizeof(opts->filepath), "//", DATA_("untitled"), nullptr);
+ BLI_path_join(opts->filepath, sizeof(opts->filepath), "//", DATA_("untitled"));
BLI_path_abs(opts->filepath, BKE_main_blendfile_path(bmain));
}
}
else {
- BLI_path_join(opts->filepath, sizeof(opts->filepath), "//", ima->id.name + 2, nullptr);
+ BLI_path_join(opts->filepath, sizeof(opts->filepath), "//", ima->id.name + 2);
BLI_path_make_safe(opts->filepath);
BLI_path_abs(opts->filepath, is_prev_save ? G.ima : BKE_main_blendfile_path(bmain));
}
diff --git a/source/blender/blenkernel/intern/instances.cc b/source/blender/blenkernel/intern/instances.cc
new file mode 100644
index 00000000000..dd759453630
--- /dev/null
+++ b/source/blender/blenkernel/intern/instances.cc
@@ -0,0 +1,348 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BLI_cpp_type_make.hh"
+#include "BLI_rand.hh"
+#include "BLI_task.hh"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_geometry_set.hh"
+#include "BKE_instances.hh"
+
+BLI_CPP_TYPE_MAKE(InstanceReference, blender::bke::InstanceReference, CPPTypeFlags::None)
+
+namespace blender::bke {
+
+InstanceReference::InstanceReference(GeometrySet geometry_set)
+ : type_(Type::GeometrySet),
+ geometry_set_(std::make_unique<GeometrySet>(std::move(geometry_set)))
+{
+}
+
+void InstanceReference::ensure_owns_direct_data()
+{
+ if (type_ != Type::GeometrySet) {
+ return;
+ }
+ geometry_set_->ensure_owns_direct_data();
+}
+
+bool InstanceReference::owns_direct_data() const
+{
+ if (type_ != Type::GeometrySet) {
+ /* The object and collection instances are not direct data. */
+ return true;
+ }
+ return geometry_set_->owns_direct_data();
+}
+
+Instances::Instances(const Instances &other)
+ : references_(other.references_),
+ reference_handles_(other.reference_handles_),
+ transforms_(other.transforms_),
+ almost_unique_ids_(other.almost_unique_ids_),
+ attributes_(other.attributes_)
+{
+}
+
+void Instances::reserve(int min_capacity)
+{
+ reference_handles_.reserve(min_capacity);
+ transforms_.reserve(min_capacity);
+ attributes_.reallocate(min_capacity);
+}
+
+void Instances::resize(int capacity)
+{
+ reference_handles_.resize(capacity);
+ transforms_.resize(capacity);
+ attributes_.reallocate(capacity);
+}
+
+void Instances::add_instance(const int instance_handle, const float4x4 &transform)
+{
+ BLI_assert(instance_handle >= 0);
+ BLI_assert(instance_handle < references_.size());
+ reference_handles_.append(instance_handle);
+ transforms_.append(transform);
+ attributes_.reallocate(this->instances_num());
+}
+
+blender::Span<int> Instances::reference_handles() const
+{
+ return reference_handles_;
+}
+
+blender::MutableSpan<int> Instances::reference_handles()
+{
+ return reference_handles_;
+}
+
+blender::MutableSpan<blender::float4x4> Instances::transforms()
+{
+ return transforms_;
+}
+blender::Span<blender::float4x4> Instances::transforms() const
+{
+ return transforms_;
+}
+
+GeometrySet &Instances::geometry_set_from_reference(const int reference_index)
+{
+ /* If this assert fails, it means #ensure_geometry_instances must be called first or that the
+ * reference can't be converted to a geometry set. */
+ BLI_assert(references_[reference_index].type() == InstanceReference::Type::GeometrySet);
+
+ /* The const cast is okay because the instance's hash in the set
+ * is not changed by adjusting the data inside the geometry set. */
+ return const_cast<GeometrySet &>(references_[reference_index].geometry_set());
+}
+
+int Instances::add_reference(const InstanceReference &reference)
+{
+ return references_.index_of_or_add_as(reference);
+}
+
+blender::Span<InstanceReference> Instances::references() const
+{
+ return references_;
+}
+
+template<typename T>
+static void copy_data_based_on_mask(Span<T> src, MutableSpan<T> dst, IndexMask mask)
+{
+ BLI_assert(src.data() != dst.data());
+ using namespace blender;
+ threading::parallel_for(mask.index_range(), 1024, [&](IndexRange range) {
+ for (const int i : range) {
+ dst[i] = src[mask[i]];
+ }
+ });
+}
+
+void Instances::remove(const IndexMask mask)
+{
+ using namespace blender;
+ if (mask.is_range() && mask.as_range().start() == 0) {
+ /* Deleting from the end of the array can be much faster since no data has to be shifted. */
+ this->resize(mask.size());
+ this->remove_unused_references();
+ return;
+ }
+
+ Vector<int> new_handles(mask.size());
+ copy_data_based_on_mask<int>(this->reference_handles(), new_handles, mask);
+ reference_handles_ = std::move(new_handles);
+ Vector<float4x4> new_transforms(mask.size());
+ copy_data_based_on_mask<float4x4>(this->transforms(), new_transforms, mask);
+ transforms_ = std::move(new_transforms);
+
+ const bke::CustomDataAttributes &src_attributes = attributes_;
+
+ bke::CustomDataAttributes dst_attributes;
+ dst_attributes.reallocate(mask.size());
+
+ src_attributes.foreach_attribute(
+ [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData &meta_data) {
+ if (!id.should_be_kept()) {
+ return true;
+ }
+
+ GSpan src = *src_attributes.get_for_read(id);
+ dst_attributes.create(id, meta_data.data_type);
+ GMutableSpan dst = *dst_attributes.get_for_write(id);
+
+ attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ copy_data_based_on_mask<T>(src.typed<T>(), dst.typed<T>(), mask);
+ });
+ return true;
+ },
+ ATTR_DOMAIN_INSTANCE);
+
+ attributes_ = std::move(dst_attributes);
+ this->remove_unused_references();
+}
+
+void Instances::remove_unused_references()
+{
+ using namespace blender;
+ using namespace blender::bke;
+
+ const int tot_instances = this->instances_num();
+ const int tot_references_before = references_.size();
+
+ if (tot_instances == 0) {
+ /* If there are no instances, no reference is needed. */
+ references_.clear();
+ return;
+ }
+ if (tot_references_before == 1) {
+ /* There is only one reference and at least one instance. So the only existing reference is
+ * used. Nothing to do here. */
+ return;
+ }
+
+ Array<bool> usage_by_handle(tot_references_before, false);
+ std::mutex mutex;
+
+ /* Loop over all instances to see which references are used. */
+ threading::parallel_for(IndexRange(tot_instances), 1000, [&](IndexRange range) {
+ /* Use local counter to avoid lock contention. */
+ Array<bool> local_usage_by_handle(tot_references_before, false);
+
+ for (const int i : range) {
+ const int handle = reference_handles_[i];
+ BLI_assert(handle >= 0 && handle < tot_references_before);
+ local_usage_by_handle[handle] = true;
+ }
+
+ std::lock_guard lock{mutex};
+ for (const int i : IndexRange(tot_references_before)) {
+ usage_by_handle[i] |= local_usage_by_handle[i];
+ }
+ });
+
+ if (!usage_by_handle.as_span().contains(false)) {
+ /* All references are used. */
+ return;
+ }
+
+ /* Create new references and a mapping for the handles. */
+ Vector<int> handle_mapping;
+ VectorSet<InstanceReference> new_references;
+ int next_new_handle = 0;
+ bool handles_have_to_be_updated = false;
+ for (const int old_handle : IndexRange(tot_references_before)) {
+ if (!usage_by_handle[old_handle]) {
+ /* Add some dummy value. It won't be read again. */
+ handle_mapping.append(-1);
+ }
+ else {
+ const InstanceReference &reference = references_[old_handle];
+ handle_mapping.append(next_new_handle);
+ new_references.add_new(reference);
+ if (old_handle != next_new_handle) {
+ handles_have_to_be_updated = true;
+ }
+ next_new_handle++;
+ }
+ }
+ references_ = new_references;
+
+ if (!handles_have_to_be_updated) {
+ /* All remaining handles are the same as before, so they don't have to be updated. This happens
+ * when unused handles are only at the end. */
+ return;
+ }
+
+ /* Update handles of instances. */
+ threading::parallel_for(IndexRange(tot_instances), 1000, [&](IndexRange range) {
+ for (const int i : range) {
+ reference_handles_[i] = handle_mapping[reference_handles_[i]];
+ }
+ });
+}
+
+int Instances::instances_num() const
+{
+ return transforms_.size();
+}
+
+int Instances::references_num() const
+{
+ return references_.size();
+}
+
+bool Instances::owns_direct_data() const
+{
+ for (const InstanceReference &reference : references_) {
+ if (!reference.owns_direct_data()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void Instances::ensure_owns_direct_data()
+{
+ for (const InstanceReference &const_reference : references_) {
+ /* Const cast is fine because we are not changing anything that would change the hash of the
+ * reference. */
+ InstanceReference &reference = const_cast<InstanceReference &>(const_reference);
+ reference.ensure_owns_direct_data();
+ }
+}
+
+static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids)
+{
+ using namespace blender;
+ Array<int> unique_ids(original_ids.size());
+
+ Set<int> used_unique_ids;
+ used_unique_ids.reserve(original_ids.size());
+ Vector<int> instances_with_id_collision;
+ for (const int instance_index : original_ids.index_range()) {
+ const int original_id = original_ids[instance_index];
+ if (used_unique_ids.add(original_id)) {
+ /* The original id has not been used by another instance yet. */
+ unique_ids[instance_index] = original_id;
+ }
+ else {
+ /* The original id of this instance collided with a previous instance, it needs to be looked
+ * at again in a second pass. Don't generate a new random id here, because this might collide
+ * with other existing ids. */
+ instances_with_id_collision.append(instance_index);
+ }
+ }
+
+ Map<int, RandomNumberGenerator> generator_by_original_id;
+ for (const int instance_index : instances_with_id_collision) {
+ const int original_id = original_ids[instance_index];
+ RandomNumberGenerator &rng = generator_by_original_id.lookup_or_add_cb(original_id, [&]() {
+ RandomNumberGenerator rng;
+ rng.seed_random(original_id);
+ return rng;
+ });
+
+ const int max_iteration = 100;
+ for (int iteration = 0;; iteration++) {
+ /* Try generating random numbers until an unused one has been found. */
+ const int random_id = rng.get_int32();
+ if (used_unique_ids.add(random_id)) {
+ /* This random id is not used by another instance. */
+ unique_ids[instance_index] = random_id;
+ break;
+ }
+ if (iteration == max_iteration) {
+ /* It seems to be very unlikely that we ever run into this case (assuming there are less
+ * than 2^30 instances). However, if that happens, it's better to use an id that is not
+ * unique than to be stuck in an infinite loop. */
+ unique_ids[instance_index] = original_id;
+ break;
+ }
+ }
+ }
+
+ return unique_ids;
+}
+
+blender::Span<int> Instances::almost_unique_ids() const
+{
+ std::lock_guard lock(almost_unique_ids_mutex_);
+ std::optional<GSpan> instance_ids_gspan = attributes_.get_for_read("id");
+ if (instance_ids_gspan) {
+ Span<int> instance_ids = instance_ids_gspan->typed<int>();
+ if (almost_unique_ids_.size() != instance_ids.size()) {
+ almost_unique_ids_ = generate_unique_instance_ids(instance_ids);
+ }
+ }
+ else {
+ almost_unique_ids_.reinitialize(this->instances_num());
+ for (const int i : almost_unique_ids_.index_range()) {
+ almost_unique_ids_[i] = i;
+ }
+ }
+ return almost_unique_ids_;
+}
+
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index fcb0adfde34..06d69b6ff61 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -1049,7 +1049,7 @@ static void layer_collection_objects_sync(ViewLayer *view_layer,
}
/* Holdout and indirect only */
- if ((layer->flag & LAYER_COLLECTION_HOLDOUT) || (base->object->visibility_flag & OB_HOLDOUT)) {
+ if ((layer->flag & LAYER_COLLECTION_HOLDOUT)) {
base->flag_from_collection |= BASE_HOLDOUT;
}
if (layer->flag & LAYER_COLLECTION_INDIRECT_ONLY) {
diff --git a/source/blender/blenkernel/intern/mball_tessellate.cc b/source/blender/blenkernel/intern/mball_tessellate.cc
index 5e8d2bc6d76..bb3713e770a 100644
--- a/source/blender/blenkernel/intern/mball_tessellate.cc
+++ b/source/blender/blenkernel/intern/mball_tessellate.cc
@@ -1498,7 +1498,7 @@ Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob)
for (int i = 0; i < mesh->totvert; i++) {
normalize_v3(process.no[i]);
}
- mesh->runtime.vert_normals = process.no;
+ mesh->runtime->vert_normals = process.no;
BKE_mesh_vertex_normals_clear_dirty(mesh);
mesh->totloop = loop_offset;
diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc
index 9e7821428d1..0018c217964 100644
--- a/source/blender/blenkernel/intern/mesh.cc
+++ b/source/blender/blenkernel/intern/mesh.cc
@@ -89,7 +89,7 @@ static void mesh_init_data(ID *id)
CustomData_reset(&mesh->pdata);
CustomData_reset(&mesh->ldata);
- BKE_mesh_runtime_init_data(mesh);
+ mesh->runtime = new blender::bke::MeshRuntime();
/* A newly created mesh does not have normals, so tag them dirty. This will be cleared
* by #BKE_mesh_vertex_normals_clear_dirty or #BKE_mesh_poly_normals_ensure. */
@@ -103,14 +103,19 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
Mesh *mesh_dst = (Mesh *)id_dst;
const Mesh *mesh_src = (const Mesh *)id_src;
- BKE_mesh_runtime_reset_on_copy(mesh_dst, flag);
+ mesh_dst->runtime = new blender::bke::MeshRuntime();
+ mesh_dst->runtime->deformed_only = mesh_src->runtime->deformed_only;
+ mesh_dst->runtime->wrapper_type = mesh_src->runtime->wrapper_type;
+ mesh_dst->runtime->wrapper_type_finalize = mesh_src->runtime->wrapper_type_finalize;
+ mesh_dst->runtime->subsurf_runtime_data = mesh_src->runtime->subsurf_runtime_data;
+ mesh_dst->runtime->cd_mask_extra = mesh_src->runtime->cd_mask_extra;
/* Copy face dot tags, since meshes may be duplicated after a subsurf modifier
* or node, but we still need to be able to draw face center vertices. */
- mesh_dst->runtime.subsurf_face_dot_tags = static_cast<uint32_t *>(
- MEM_dupallocN(mesh_src->runtime.subsurf_face_dot_tags));
+ mesh_dst->runtime->subsurf_face_dot_tags = static_cast<uint32_t *>(
+ MEM_dupallocN(mesh_src->runtime->subsurf_face_dot_tags));
if ((mesh_src->id.tag & LIB_TAG_NO_MAIN) == 0) {
/* This is a direct copy of a main mesh, so for now it has the same topology. */
- mesh_dst->runtime.deformed_only = true;
+ mesh_dst->runtime->deformed_only = true;
}
/* This option is set for run-time meshes that have been copied from the current objects mode.
* Currently this is used for edit-mesh although it could be used for sculpt or other
@@ -121,7 +126,7 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
*
* While this could be the callers responsibility, keep here since it's
* highly unlikely we want to create a duplicate and not use it for drawing. */
- mesh_dst->runtime.is_original_bmesh = false;
+ mesh_dst->runtime->is_original_bmesh = false;
/* Only do tessface if we have no polys. */
const bool do_tessface = ((mesh_src->totface != 0) && (mesh_src->totpoly == 0));
@@ -194,6 +199,8 @@ static void mesh_free_data(ID *id)
BKE_mesh_runtime_free_data(mesh);
mesh_clear_geometry(mesh);
MEM_SAFE_FREE(mesh->mat);
+
+ delete mesh->runtime;
}
static void mesh_foreach_id(ID *id, LibraryForeachIDData *data)
@@ -229,7 +236,7 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address
mesh->mface = nullptr;
mesh->totface = 0;
memset(&mesh->fdata, 0, sizeof(mesh->fdata));
- mesh->runtime = blender::dna::shallow_zero_initialize();
+ mesh->runtime = nullptr;
/* Do not store actual geometry data in case this is a library override ID. */
if (ID_IS_OVERRIDE_LIBRARY(mesh) && !is_undo) {
@@ -339,8 +346,7 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id)
mesh->texflag &= ~ME_AUTOSPACE_EVALUATED;
mesh->edit_mesh = nullptr;
- mesh->runtime = blender::dna::shallow_zero_initialize();
- BKE_mesh_runtime_init_data(mesh);
+ mesh->runtime = new blender::bke::MeshRuntime();
/* happens with old files */
if (mesh->mselect == nullptr) {
@@ -1137,7 +1143,7 @@ static void ensure_orig_index_layer(CustomData &data, const int size)
void BKE_mesh_ensure_default_orig_index_customdata(Mesh *mesh)
{
- BLI_assert(mesh->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA);
+ BLI_assert(mesh->runtime->wrapper_type == ME_WRAPPER_TYPE_MDATA);
BKE_mesh_ensure_default_orig_index_customdata_no_check(mesh);
}
@@ -2106,8 +2112,8 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
}
/* Update normals manually to avoid recalculation after this operation. */
- mesh->runtime.vert_normals = (float(*)[3])MEM_reallocN(mesh->runtime.vert_normals,
- sizeof(float[3]) * mesh->totvert);
+ mesh->runtime->vert_normals = (float(*)[3])MEM_reallocN(mesh->runtime->vert_normals,
+ sizeof(float[3]) * mesh->totvert);
/* Perform actual split of vertices and edges. */
split_faces_split_new_verts(mesh, new_verts, num_new_verts);
@@ -2141,10 +2147,10 @@ void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh)
/* We are here because something did change in the mesh. This means we can not trust the existing
* evaluated mesh, and we don't know what parts of the mesh did change. So we simply delete the
* evaluated mesh and let objects to re-create it with updated settings. */
- if (mesh->runtime.mesh_eval != nullptr) {
- mesh->runtime.mesh_eval->edit_mesh = nullptr;
- BKE_id_free(nullptr, mesh->runtime.mesh_eval);
- mesh->runtime.mesh_eval = nullptr;
+ if (mesh->runtime->mesh_eval != nullptr) {
+ mesh->runtime->mesh_eval->edit_mesh = nullptr;
+ BKE_id_free(nullptr, mesh->runtime->mesh_eval);
+ mesh->runtime->mesh_eval = nullptr;
}
if (DEG_is_active(depsgraph)) {
Mesh *mesh_orig = (Mesh *)DEG_get_original_id(&mesh->id);
diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc
index b4f729ca507..027423f5774 100644
--- a/source/blender/blenkernel/intern/mesh_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_convert.cc
@@ -903,7 +903,7 @@ static Mesh *mesh_new_from_mesh(Object *object, Mesh *mesh)
{
/* While we could copy this into the new mesh,
* add the data to 'mesh' so future calls to this function don't need to re-convert the data. */
- if (mesh->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
+ if (mesh->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) {
BKE_mesh_wrapper_ensure_mdata(mesh);
}
else {
diff --git a/source/blender/blenkernel/intern/mesh_debug.cc b/source/blender/blenkernel/intern/mesh_debug.cc
index ba4f25c74ee..6cf237a7c8c 100644
--- a/source/blender/blenkernel/intern/mesh_debug.cc
+++ b/source/blender/blenkernel/intern/mesh_debug.cc
@@ -41,9 +41,9 @@ char *BKE_mesh_debug_info(const Mesh *me)
BLI_dynstr_appendf(dynstr, " 'totface': %d,\n", me->totface);
BLI_dynstr_appendf(dynstr, " 'totpoly': %d,\n", me->totpoly);
- BLI_dynstr_appendf(dynstr, " 'runtime.deformed_only': %d,\n", me->runtime.deformed_only);
+ BLI_dynstr_appendf(dynstr, " 'runtime.deformed_only': %d,\n", me->runtime->deformed_only);
BLI_dynstr_appendf(
- dynstr, " 'runtime.is_original_bmesh': %d,\n", me->runtime.is_original_bmesh);
+ dynstr, " 'runtime->is_original_bmesh': %d,\n", me->runtime->is_original_bmesh);
BLI_dynstr_append(dynstr, " 'vert_layers': (\n");
CustomData_debug_info_from_layers(&me->vdata, indent8, dynstr);
diff --git a/source/blender/blenkernel/intern/mesh_fair.cc b/source/blender/blenkernel/intern/mesh_fair.cc
index 5369bc782b6..960e6c43103 100644
--- a/source/blender/blenkernel/intern/mesh_fair.cc
+++ b/source/blender/blenkernel/intern/mesh_fair.cc
@@ -221,7 +221,7 @@ class MeshFairingContext : public FairingContext {
}
}
- loop_to_poly_map_ = blender::mesh_topology::build_loop_to_poly_map(mpoly_, mloop_.size());
+ loop_to_poly_map_ = blender::bke::mesh_topology::build_loop_to_poly_map(mpoly_, mloop_.size());
}
~MeshFairingContext() override
diff --git a/source/blender/blenkernel/intern/mesh_iterators.cc b/source/blender/blenkernel/intern/mesh_iterators.cc
index cf2518d7c9b..a99e9b2348d 100644
--- a/source/blender/blenkernel/intern/mesh_iterators.cc
+++ b/source/blender/blenkernel/intern/mesh_iterators.cc
@@ -36,18 +36,18 @@ void BKE_mesh_foreach_mapped_vert(
void *userData,
MeshForeachFlag flag)
{
- if (mesh->edit_mesh != nullptr && mesh->runtime.edit_data != nullptr) {
+ if (mesh->edit_mesh != nullptr && mesh->runtime->edit_data != nullptr) {
BMEditMesh *em = mesh->edit_mesh;
BMesh *bm = em->bm;
BMIter iter;
BMVert *eve;
int i;
- if (mesh->runtime.edit_data->vertexCos != nullptr) {
- const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
+ if (mesh->runtime->edit_data->vertexCos != nullptr) {
+ const float(*vertexCos)[3] = mesh->runtime->edit_data->vertexCos;
const float(*vertexNos)[3];
if (flag & MESH_FOREACH_USE_NORMAL) {
- BKE_editmesh_cache_ensure_vert_normals(em, mesh->runtime.edit_data);
- vertexNos = mesh->runtime.edit_data->vertexNos;
+ BKE_editmesh_cache_ensure_vert_normals(em, mesh->runtime->edit_data);
+ vertexNos = mesh->runtime->edit_data->vertexNos;
}
else {
vertexNos = nullptr;
@@ -96,14 +96,14 @@ void BKE_mesh_foreach_mapped_edge(
void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]),
void *userData)
{
- if (mesh->edit_mesh != nullptr && mesh->runtime.edit_data) {
+ if (mesh->edit_mesh != nullptr && mesh->runtime->edit_data) {
BMEditMesh *em = mesh->edit_mesh;
BMesh *bm = em->bm;
BMIter iter;
BMEdge *eed;
int i;
- if (mesh->runtime.edit_data->vertexCos != nullptr) {
- const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
+ if (mesh->runtime->edit_data->vertexCos != nullptr) {
+ const float(*vertexCos)[3] = mesh->runtime->edit_data->vertexCos;
BM_mesh_elem_index_ensure(bm, BM_VERT);
BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
@@ -154,13 +154,13 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh,
/* We can't use `dm->getLoopDataLayout(dm)` here,
* we want to always access `dm->loopData`, `EditDerivedBMesh` would
* return loop data from BMesh itself. */
- if (mesh->edit_mesh != nullptr && mesh->runtime.edit_data) {
+ if (mesh->edit_mesh != nullptr && mesh->runtime->edit_data) {
BMEditMesh *em = mesh->edit_mesh;
BMesh *bm = em->bm;
BMIter iter;
BMFace *efa;
- const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
+ const float(*vertexCos)[3] = mesh->runtime->edit_data->vertexCos;
/* XXX: investigate using EditMesh data. */
const float(*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ?
@@ -231,7 +231,7 @@ void BKE_mesh_foreach_mapped_face_center(
void *userData,
MeshForeachFlag flag)
{
- if (mesh->edit_mesh != nullptr && mesh->runtime.edit_data != nullptr) {
+ if (mesh->edit_mesh != nullptr && mesh->runtime->edit_data != nullptr) {
BMEditMesh *em = mesh->edit_mesh;
BMesh *bm = em->bm;
const float(*polyCos)[3];
@@ -240,12 +240,12 @@ void BKE_mesh_foreach_mapped_face_center(
BMIter iter;
int i;
- BKE_editmesh_cache_ensure_poly_centers(em, mesh->runtime.edit_data);
- polyCos = mesh->runtime.edit_data->polyCos; /* always set */
+ BKE_editmesh_cache_ensure_poly_centers(em, mesh->runtime->edit_data);
+ polyCos = mesh->runtime->edit_data->polyCos; /* always set */
if (flag & MESH_FOREACH_USE_NORMAL) {
- BKE_editmesh_cache_ensure_poly_normals(em, mesh->runtime.edit_data);
- polyNos = mesh->runtime.edit_data->polyNos; /* maybe nullptr */
+ BKE_editmesh_cache_ensure_poly_normals(em, mesh->runtime->edit_data);
+ polyNos = mesh->runtime->edit_data->polyNos; /* maybe nullptr */
}
else {
polyNos = nullptr;
@@ -317,7 +317,7 @@ void BKE_mesh_foreach_mapped_subdiv_face_center(
BKE_mesh_vertex_normals_ensure(mesh) :
nullptr;
const int *index = static_cast<const int *>(CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX));
- const BLI_bitmap *facedot_tags = mesh->runtime.subsurf_face_dot_tags;
+ const BLI_bitmap *facedot_tags = mesh->runtime->subsurf_face_dot_tags;
BLI_assert(facedot_tags != nullptr);
if (index) {
diff --git a/source/blender/blenkernel/intern/mesh_mapping.cc b/source/blender/blenkernel/intern/mesh_mapping.cc
index 667802d5f48..ed4ae94da7f 100644
--- a/source/blender/blenkernel/intern/mesh_mapping.cc
+++ b/source/blender/blenkernel/intern/mesh_mapping.cc
@@ -553,7 +553,7 @@ void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map,
*r_mem = indices;
}
-namespace blender::mesh_topology {
+namespace blender::bke::mesh_topology {
Array<int> build_loop_to_poly_map(const Span<MPoly> polys, const int loops_num)
{
@@ -586,7 +586,7 @@ Array<Vector<int>> build_vert_to_loop_map(const Span<MLoop> loops, const int ver
return map;
}
-} // namespace blender::mesh_topology
+} // namespace blender::bke::mesh_topology
/** \} */
diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc
index 76f2078e6c8..ebb5a72d137 100644
--- a/source/blender/blenkernel/intern/mesh_normals.cc
+++ b/source/blender/blenkernel/intern/mesh_normals.cc
@@ -95,72 +95,72 @@ static void add_v3_v3_atomic(float r[3], const float a[3])
void BKE_mesh_normals_tag_dirty(Mesh *mesh)
{
- mesh->runtime.vert_normals_dirty = true;
- mesh->runtime.poly_normals_dirty = true;
+ mesh->runtime->vert_normals_dirty = true;
+ mesh->runtime->poly_normals_dirty = true;
}
float (*BKE_mesh_vertex_normals_for_write(Mesh *mesh))[3]
{
- if (mesh->runtime.vert_normals == nullptr) {
- mesh->runtime.vert_normals = (float(*)[3])MEM_malloc_arrayN(
+ if (mesh->runtime->vert_normals == nullptr) {
+ mesh->runtime->vert_normals = (float(*)[3])MEM_malloc_arrayN(
mesh->totvert, sizeof(float[3]), __func__);
}
- BLI_assert(MEM_allocN_len(mesh->runtime.vert_normals) >= sizeof(float[3]) * mesh->totvert);
+ BLI_assert(MEM_allocN_len(mesh->runtime->vert_normals) >= sizeof(float[3]) * mesh->totvert);
- return mesh->runtime.vert_normals;
+ return mesh->runtime->vert_normals;
}
float (*BKE_mesh_poly_normals_for_write(Mesh *mesh))[3]
{
- if (mesh->runtime.poly_normals == nullptr) {
- mesh->runtime.poly_normals = (float(*)[3])MEM_malloc_arrayN(
+ if (mesh->runtime->poly_normals == nullptr) {
+ mesh->runtime->poly_normals = (float(*)[3])MEM_malloc_arrayN(
mesh->totpoly, sizeof(float[3]), __func__);
}
- BLI_assert(MEM_allocN_len(mesh->runtime.poly_normals) >= sizeof(float[3]) * mesh->totpoly);
+ BLI_assert(MEM_allocN_len(mesh->runtime->poly_normals) >= sizeof(float[3]) * mesh->totpoly);
- return mesh->runtime.poly_normals;
+ return mesh->runtime->poly_normals;
}
void BKE_mesh_vertex_normals_clear_dirty(Mesh *mesh)
{
- mesh->runtime.vert_normals_dirty = false;
+ mesh->runtime->vert_normals_dirty = false;
BKE_mesh_assert_normals_dirty_or_calculated(mesh);
}
void BKE_mesh_poly_normals_clear_dirty(Mesh *mesh)
{
- mesh->runtime.poly_normals_dirty = false;
+ mesh->runtime->poly_normals_dirty = false;
BKE_mesh_assert_normals_dirty_or_calculated(mesh);
}
bool BKE_mesh_vertex_normals_are_dirty(const Mesh *mesh)
{
- return mesh->runtime.vert_normals_dirty;
+ return mesh->runtime->vert_normals_dirty;
}
bool BKE_mesh_poly_normals_are_dirty(const Mesh *mesh)
{
- return mesh->runtime.poly_normals_dirty;
+ return mesh->runtime->poly_normals_dirty;
}
void BKE_mesh_clear_derived_normals(Mesh *mesh)
{
- MEM_SAFE_FREE(mesh->runtime.vert_normals);
- MEM_SAFE_FREE(mesh->runtime.poly_normals);
+ MEM_SAFE_FREE(mesh->runtime->vert_normals);
+ MEM_SAFE_FREE(mesh->runtime->poly_normals);
- mesh->runtime.vert_normals_dirty = true;
- mesh->runtime.poly_normals_dirty = true;
+ mesh->runtime->vert_normals_dirty = true;
+ mesh->runtime->poly_normals_dirty = true;
}
void BKE_mesh_assert_normals_dirty_or_calculated(const Mesh *mesh)
{
- if (!mesh->runtime.vert_normals_dirty) {
- BLI_assert(mesh->runtime.vert_normals || mesh->totvert == 0);
+ if (!mesh->runtime->vert_normals_dirty) {
+ BLI_assert(mesh->runtime->vert_normals || mesh->totvert == 0);
}
- if (!mesh->runtime.poly_normals_dirty) {
- BLI_assert(mesh->runtime.poly_normals || mesh->totpoly == 0);
+ if (!mesh->runtime->poly_normals_dirty) {
+ BLI_assert(mesh->runtime->poly_normals || mesh->totpoly == 0);
}
}
@@ -348,20 +348,18 @@ void BKE_mesh_calc_normals_poly_and_vertex(const MVert *mvert,
const float (*BKE_mesh_vertex_normals_ensure(const Mesh *mesh))[3]
{
if (!BKE_mesh_vertex_normals_are_dirty(mesh)) {
- BLI_assert(mesh->runtime.vert_normals != nullptr || mesh->totvert == 0);
- return mesh->runtime.vert_normals;
+ BLI_assert(mesh->runtime->vert_normals != nullptr || mesh->totvert == 0);
+ return mesh->runtime->vert_normals;
}
if (mesh->totvert == 0) {
return nullptr;
}
- ThreadMutex *normals_mutex = (ThreadMutex *)mesh->runtime.normals_mutex;
- BLI_mutex_lock(normals_mutex);
+ std::lock_guard lock{mesh->runtime->normals_mutex};
if (!BKE_mesh_vertex_normals_are_dirty(mesh)) {
- BLI_assert(mesh->runtime.vert_normals != nullptr);
- BLI_mutex_unlock(normals_mutex);
- return mesh->runtime.vert_normals;
+ BLI_assert(mesh->runtime->vert_normals != nullptr);
+ return mesh->runtime->vert_normals;
}
float(*vert_normals)[3];
@@ -390,27 +388,24 @@ const float (*BKE_mesh_vertex_normals_ensure(const Mesh *mesh))[3]
BKE_mesh_poly_normals_clear_dirty(&mesh_mutable);
});
- BLI_mutex_unlock(normals_mutex);
return vert_normals;
}
const float (*BKE_mesh_poly_normals_ensure(const Mesh *mesh))[3]
{
if (!BKE_mesh_poly_normals_are_dirty(mesh)) {
- BLI_assert(mesh->runtime.poly_normals != nullptr || mesh->totpoly == 0);
- return mesh->runtime.poly_normals;
+ BLI_assert(mesh->runtime->poly_normals != nullptr || mesh->totpoly == 0);
+ return mesh->runtime->poly_normals;
}
if (mesh->totpoly == 0) {
return nullptr;
}
- ThreadMutex *normals_mutex = (ThreadMutex *)mesh->runtime.normals_mutex;
- BLI_mutex_lock(normals_mutex);
+ std::lock_guard lock{mesh->runtime->normals_mutex};
if (!BKE_mesh_poly_normals_are_dirty(mesh)) {
- BLI_assert(mesh->runtime.poly_normals != nullptr);
- BLI_mutex_unlock(normals_mutex);
- return mesh->runtime.poly_normals;
+ BLI_assert(mesh->runtime->poly_normals != nullptr);
+ return mesh->runtime->poly_normals;
}
float(*poly_normals)[3];
@@ -435,13 +430,12 @@ const float (*BKE_mesh_poly_normals_ensure(const Mesh *mesh))[3]
BKE_mesh_poly_normals_clear_dirty(&mesh_mutable);
});
- BLI_mutex_unlock(normals_mutex);
return poly_normals;
}
void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
{
- switch ((eMeshWrapperType)mesh->runtime.wrapper_type) {
+ switch (mesh->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
BKE_mesh_vertex_normals_ensure(mesh);
@@ -449,7 +443,7 @@ void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
break;
case ME_WRAPPER_TYPE_BMESH: {
struct BMEditMesh *em = mesh->edit_mesh;
- EditMeshData *emd = mesh->runtime.edit_data;
+ EditMeshData *emd = mesh->runtime->edit_data;
if (emd->vertexCos) {
BKE_editmesh_cache_ensure_vert_normals(em, emd);
BKE_editmesh_cache_ensure_poly_normals(em, emd);
diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c
index cb05d33bc2e..90798ea593d 100644
--- a/source/blender/blenkernel/intern/mesh_remap.c
+++ b/source/blender/blenkernel/intern/mesh_remap.c
@@ -1529,7 +1529,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
BLI_bitmap *looptri_active;
looptri_src = BKE_mesh_runtime_looptri_ensure(me_src);
- num_looptri_src = me_src->runtime.looptris.len;
+ num_looptri_src = BKE_mesh_runtime_looptri_len(me_src);
looptri_active = BLI_BITMAP_NEW((size_t)num_looptri_src, __func__);
for (tindex = 0; tindex < num_trees; tindex++) {
diff --git a/source/blender/blenkernel/intern/mesh_runtime.cc b/source/blender/blenkernel/intern/mesh_runtime.cc
index bd9f8242274..e90a298ad8d 100644
--- a/source/blender/blenkernel/intern/mesh_runtime.cc
+++ b/source/blender/blenkernel/intern/mesh_runtime.cc
@@ -17,6 +17,7 @@
#include "BLI_task.hh"
#include "BKE_bvhutils.h"
+#include "BKE_editmesh_cache.h"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
@@ -30,81 +31,17 @@ using blender::Span;
/** \name Mesh Runtime Struct Utils
* \{ */
-/**
- * \brief Initialize the runtime mutexes of the given mesh.
- *
- * Any existing mutexes will be overridden.
- */
-static void mesh_runtime_init_mutexes(Mesh *mesh)
-{
- mesh->runtime.eval_mutex = MEM_new<ThreadMutex>("mesh runtime eval_mutex");
- BLI_mutex_init(static_cast<ThreadMutex *>(mesh->runtime.eval_mutex));
- mesh->runtime.normals_mutex = MEM_new<ThreadMutex>("mesh runtime normals_mutex");
- BLI_mutex_init(static_cast<ThreadMutex *>(mesh->runtime.normals_mutex));
- mesh->runtime.render_mutex = MEM_new<ThreadMutex>("mesh runtime render_mutex");
- BLI_mutex_init(static_cast<ThreadMutex *>(mesh->runtime.render_mutex));
-}
-
-/**
- * \brief free the mutexes of the given mesh runtime.
- */
-static void mesh_runtime_free_mutexes(Mesh *mesh)
-{
- if (mesh->runtime.eval_mutex != nullptr) {
- BLI_mutex_end(static_cast<ThreadMutex *>(mesh->runtime.eval_mutex));
- MEM_freeN(mesh->runtime.eval_mutex);
- mesh->runtime.eval_mutex = nullptr;
- }
- if (mesh->runtime.normals_mutex != nullptr) {
- BLI_mutex_end(static_cast<ThreadMutex *>(mesh->runtime.normals_mutex));
- MEM_freeN(mesh->runtime.normals_mutex);
- mesh->runtime.normals_mutex = nullptr;
- }
- if (mesh->runtime.render_mutex != nullptr) {
- BLI_mutex_end(static_cast<ThreadMutex *>(mesh->runtime.render_mutex));
- MEM_freeN(mesh->runtime.render_mutex);
- mesh->runtime.render_mutex = nullptr;
- }
-}
-
-void BKE_mesh_runtime_init_data(Mesh *mesh)
-{
- mesh_runtime_init_mutexes(mesh);
-}
-
void BKE_mesh_runtime_free_data(Mesh *mesh)
{
BKE_mesh_runtime_clear_cache(mesh);
- mesh_runtime_free_mutexes(mesh);
-}
-
-void BKE_mesh_runtime_reset_on_copy(Mesh *mesh, const int /*flag*/)
-{
- Mesh_Runtime *runtime = &mesh->runtime;
-
- runtime->mesh_eval = nullptr;
- runtime->edit_data = nullptr;
- runtime->batch_cache = nullptr;
- runtime->subdiv_ccg = nullptr;
- runtime->looptris = blender::dna::shallow_zero_initialize();
- runtime->bvh_cache = nullptr;
- runtime->shrinkwrap_data = nullptr;
- runtime->subsurf_face_dot_tags = nullptr;
-
- runtime->vert_normals_dirty = true;
- runtime->poly_normals_dirty = true;
- runtime->vert_normals = nullptr;
- runtime->poly_normals = nullptr;
-
- mesh_runtime_init_mutexes(mesh);
}
void BKE_mesh_runtime_clear_cache(Mesh *mesh)
{
- if (mesh->runtime.mesh_eval != nullptr) {
- mesh->runtime.mesh_eval->edit_mesh = nullptr;
- BKE_id_free(nullptr, mesh->runtime.mesh_eval);
- mesh->runtime.mesh_eval = nullptr;
+ if (mesh->runtime->mesh_eval != nullptr) {
+ mesh->runtime->mesh_eval->edit_mesh = nullptr;
+ BKE_id_free(nullptr, mesh->runtime->mesh_eval);
+ mesh->runtime->mesh_eval = nullptr;
}
BKE_mesh_runtime_clear_geometry(mesh);
BKE_mesh_batch_cache_free(mesh);
@@ -131,32 +68,32 @@ static void mesh_ensure_looptri_data(Mesh *mesh)
const uint totpoly = mesh->totpoly;
const int looptris_len = poly_to_tri_count(totpoly, mesh->totloop);
- BLI_assert(mesh->runtime.looptris.array_wip == nullptr);
+ BLI_assert(mesh->runtime->looptris.array_wip == nullptr);
- SWAP(MLoopTri *, mesh->runtime.looptris.array, mesh->runtime.looptris.array_wip);
+ SWAP(MLoopTri *, mesh->runtime->looptris.array, mesh->runtime->looptris.array_wip);
- if ((looptris_len > mesh->runtime.looptris.len_alloc) ||
- (looptris_len < mesh->runtime.looptris.len_alloc * 2) || (totpoly == 0)) {
- MEM_SAFE_FREE(mesh->runtime.looptris.array_wip);
- mesh->runtime.looptris.len_alloc = 0;
- mesh->runtime.looptris.len = 0;
+ if ((looptris_len > mesh->runtime->looptris.len_alloc) ||
+ (looptris_len < mesh->runtime->looptris.len_alloc * 2) || (totpoly == 0)) {
+ MEM_SAFE_FREE(mesh->runtime->looptris.array_wip);
+ mesh->runtime->looptris.len_alloc = 0;
+ mesh->runtime->looptris.len = 0;
}
if (totpoly) {
- if (mesh->runtime.looptris.array_wip == nullptr) {
- mesh->runtime.looptris.array_wip = static_cast<MLoopTri *>(
- MEM_malloc_arrayN(looptris_len, sizeof(*mesh->runtime.looptris.array_wip), __func__));
- mesh->runtime.looptris.len_alloc = looptris_len;
+ if (mesh->runtime->looptris.array_wip == nullptr) {
+ mesh->runtime->looptris.array_wip = static_cast<MLoopTri *>(
+ MEM_malloc_arrayN(looptris_len, sizeof(*mesh->runtime->looptris.array_wip), __func__));
+ mesh->runtime->looptris.len_alloc = looptris_len;
}
- mesh->runtime.looptris.len = looptris_len;
+ mesh->runtime->looptris.len = looptris_len;
}
}
void BKE_mesh_runtime_looptri_recalc(Mesh *mesh)
{
mesh_ensure_looptri_data(mesh);
- BLI_assert(mesh->totpoly == 0 || mesh->runtime.looptris.array_wip != nullptr);
+ BLI_assert(mesh->totpoly == 0 || mesh->runtime->looptris.array_wip != nullptr);
const Span<MVert> verts = mesh->verts();
const Span<MPoly> polys = mesh->polys();
const Span<MLoop> loops = mesh->loops();
@@ -167,7 +104,7 @@ void BKE_mesh_runtime_looptri_recalc(Mesh *mesh)
verts.data(),
mesh->totloop,
mesh->totpoly,
- mesh->runtime.looptris.array_wip,
+ mesh->runtime->looptris.array_wip,
BKE_mesh_poly_normals_ensure(mesh));
}
else {
@@ -176,43 +113,40 @@ void BKE_mesh_runtime_looptri_recalc(Mesh *mesh)
verts.data(),
mesh->totloop,
mesh->totpoly,
- mesh->runtime.looptris.array_wip);
+ mesh->runtime->looptris.array_wip);
}
- BLI_assert(mesh->runtime.looptris.array == nullptr);
- atomic_cas_ptr((void **)&mesh->runtime.looptris.array,
- mesh->runtime.looptris.array,
- mesh->runtime.looptris.array_wip);
- mesh->runtime.looptris.array_wip = nullptr;
+ BLI_assert(mesh->runtime->looptris.array == nullptr);
+ atomic_cas_ptr((void **)&mesh->runtime->looptris.array,
+ mesh->runtime->looptris.array,
+ mesh->runtime->looptris.array_wip);
+ mesh->runtime->looptris.array_wip = nullptr;
}
int BKE_mesh_runtime_looptri_len(const Mesh *mesh)
{
/* This is a ported copy of `dm_getNumLoopTri(dm)`. */
const int looptri_len = poly_to_tri_count(mesh->totpoly, mesh->totloop);
- BLI_assert(ELEM(mesh->runtime.looptris.len, 0, looptri_len));
+ BLI_assert(ELEM(mesh->runtime->looptris.len, 0, looptri_len));
return looptri_len;
}
const MLoopTri *BKE_mesh_runtime_looptri_ensure(const Mesh *mesh)
{
- ThreadMutex *mesh_eval_mutex = (ThreadMutex *)mesh->runtime.eval_mutex;
- BLI_mutex_lock(mesh_eval_mutex);
+ std::lock_guard lock{mesh->runtime->eval_mutex};
- MLoopTri *looptri = mesh->runtime.looptris.array;
+ MLoopTri *looptri = mesh->runtime->looptris.array;
if (looptri != nullptr) {
- BLI_assert(BKE_mesh_runtime_looptri_len(mesh) == mesh->runtime.looptris.len);
+ BLI_assert(BKE_mesh_runtime_looptri_len(mesh) == mesh->runtime->looptris.len);
}
else {
/* Must isolate multithreaded tasks while holding a mutex lock. */
blender::threading::isolate_task(
[&]() { BKE_mesh_runtime_looptri_recalc(const_cast<Mesh *>(mesh)); });
- looptri = mesh->runtime.looptris.array;
+ looptri = mesh->runtime->looptris.array;
}
- BLI_mutex_unlock(mesh_eval_mutex);
-
return looptri;
}
@@ -230,17 +164,17 @@ void BKE_mesh_runtime_verttri_from_looptri(MVertTri *r_verttri,
bool BKE_mesh_runtime_ensure_edit_data(struct Mesh *mesh)
{
- if (mesh->runtime.edit_data != nullptr) {
+ if (mesh->runtime->edit_data != nullptr) {
return false;
}
- mesh->runtime.edit_data = MEM_cnew<EditMeshData>(__func__);
+ mesh->runtime->edit_data = MEM_cnew<EditMeshData>(__func__);
return true;
}
bool BKE_mesh_runtime_reset_edit_data(Mesh *mesh)
{
- EditMeshData *edit_data = mesh->runtime.edit_data;
+ EditMeshData *edit_data = mesh->runtime->edit_data;
if (edit_data == nullptr) {
return false;
}
@@ -255,13 +189,13 @@ bool BKE_mesh_runtime_reset_edit_data(Mesh *mesh)
bool BKE_mesh_runtime_clear_edit_data(Mesh *mesh)
{
- if (mesh->runtime.edit_data == nullptr) {
+ if (mesh->runtime->edit_data == nullptr) {
return false;
}
BKE_mesh_runtime_reset_edit_data(mesh);
- MEM_freeN(mesh->runtime.edit_data);
- mesh->runtime.edit_data = nullptr;
+ MEM_freeN(mesh->runtime->edit_data);
+ mesh->runtime->edit_data = nullptr;
return true;
}
@@ -271,22 +205,22 @@ void BKE_mesh_runtime_clear_geometry(Mesh *mesh)
BKE_mesh_tag_coords_changed(mesh);
/* TODO(sergey): Does this really belong here? */
- if (mesh->runtime.subdiv_ccg != nullptr) {
- BKE_subdiv_ccg_destroy(mesh->runtime.subdiv_ccg);
- mesh->runtime.subdiv_ccg = nullptr;
+ if (mesh->runtime->subdiv_ccg != nullptr) {
+ BKE_subdiv_ccg_destroy(mesh->runtime->subdiv_ccg);
+ mesh->runtime->subdiv_ccg = nullptr;
}
BKE_shrinkwrap_discard_boundary_data(mesh);
- MEM_SAFE_FREE(mesh->runtime.subsurf_face_dot_tags);
+ MEM_SAFE_FREE(mesh->runtime->subsurf_face_dot_tags);
}
void BKE_mesh_tag_coords_changed(Mesh *mesh)
{
BKE_mesh_normals_tag_dirty(mesh);
- MEM_SAFE_FREE(mesh->runtime.looptris.array);
- if (mesh->runtime.bvh_cache) {
- bvhcache_free(mesh->runtime.bvh_cache);
- mesh->runtime.bvh_cache = nullptr;
+ MEM_SAFE_FREE(mesh->runtime->looptris.array);
+ if (mesh->runtime->bvh_cache) {
+ bvhcache_free(mesh->runtime->bvh_cache);
+ mesh->runtime->bvh_cache = nullptr;
}
}
@@ -305,6 +239,16 @@ void BKE_mesh_tag_coords_changed_uniformly(Mesh *mesh)
}
}
+bool BKE_mesh_is_deformed_only(const Mesh *mesh)
+{
+ return mesh->runtime->deformed_only;
+}
+
+eMeshWrapperType BKE_mesh_wrapper_type(const struct Mesh *mesh)
+{
+ return mesh->runtime->wrapper_type;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -317,13 +261,13 @@ void (*BKE_mesh_batch_cache_free_cb)(Mesh *me) = nullptr;
void BKE_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode)
{
- if (me->runtime.batch_cache) {
+ if (me->runtime->batch_cache) {
BKE_mesh_batch_cache_dirty_tag_cb(me, mode);
}
}
void BKE_mesh_batch_cache_free(Mesh *me)
{
- if (me->runtime.batch_cache) {
+ if (me->runtime->batch_cache) {
BKE_mesh_batch_cache_free_cb(me);
}
}
diff --git a/source/blender/blenkernel/intern/mesh_tangent.cc b/source/blender/blenkernel/intern/mesh_tangent.cc
index 1162986aaf5..49ea23a1552 100644
--- a/source/blender/blenkernel/intern/mesh_tangent.cc
+++ b/source/blender/blenkernel/intern/mesh_tangent.cc
@@ -570,8 +570,6 @@ void BKE_mesh_calc_loop_tangents(Mesh *me_eval,
const char (*tangent_names)[MAX_NAME],
int tangent_names_len)
{
- BKE_mesh_runtime_looptri_ensure(me_eval);
-
/* TODO(@campbellbarton): store in Mesh.runtime to avoid recalculation. */
short tangent_mask = 0;
BKE_mesh_calc_loop_tangent_ex(
@@ -579,8 +577,8 @@ void BKE_mesh_calc_loop_tangents(Mesh *me_eval,
BKE_mesh_polys(me_eval),
uint(me_eval->totpoly),
BKE_mesh_loops(me_eval),
- me_eval->runtime.looptris.array,
- uint(me_eval->runtime.looptris.len),
+ BKE_mesh_runtime_looptri_ensure(me_eval),
+ uint(BKE_mesh_runtime_looptri_len(me_eval)),
&me_eval->ldata,
calc_active_tangent,
tangent_names,
diff --git a/source/blender/blenkernel/intern/mesh_wrapper.cc b/source/blender/blenkernel/intern/mesh_wrapper.cc
index 101fad2fce8..61a95fb4d0e 100644
--- a/source/blender/blenkernel/intern/mesh_wrapper.cc
+++ b/source/blender/blenkernel/intern/mesh_wrapper.cc
@@ -57,13 +57,13 @@ Mesh *BKE_mesh_wrapper_from_editmesh_with_coords(BMEditMesh *em,
BKE_mesh_copy_parameters_for_eval(me, me_settings);
BKE_mesh_runtime_ensure_edit_data(me);
- me->runtime.wrapper_type = ME_WRAPPER_TYPE_BMESH;
+ me->runtime->wrapper_type = ME_WRAPPER_TYPE_BMESH;
if (cd_mask_extra) {
- me->runtime.cd_mask_extra = *cd_mask_extra;
+ me->runtime->cd_mask_extra = *cd_mask_extra;
}
/* Use edit-mesh directly where possible. */
- me->runtime.is_original_bmesh = true;
+ me->runtime->is_original_bmesh = true;
me->edit_mesh = static_cast<BMEditMesh *>(MEM_dupallocN(em));
me->edit_mesh->is_shallow_copy = true;
@@ -81,7 +81,7 @@ Mesh *BKE_mesh_wrapper_from_editmesh_with_coords(BMEditMesh *em,
me->totloop = 0;
#endif
- EditMeshData *edit_data = me->runtime.edit_data;
+ EditMeshData *edit_data = me->runtime->edit_data;
edit_data->vertexCos = vert_coords;
return me;
}
@@ -95,17 +95,14 @@ Mesh *BKE_mesh_wrapper_from_editmesh(BMEditMesh *em,
void BKE_mesh_wrapper_ensure_mdata(Mesh *me)
{
- ThreadMutex *mesh_eval_mutex = (ThreadMutex *)me->runtime.eval_mutex;
- BLI_mutex_lock(mesh_eval_mutex);
-
- if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA) {
- BLI_mutex_unlock(mesh_eval_mutex);
+ std::lock_guard lock{me->runtime->eval_mutex};
+ if (me->runtime->wrapper_type == ME_WRAPPER_TYPE_MDATA) {
return;
}
/* Must isolate multithreaded tasks while holding a mutex lock. */
blender::threading::isolate_task([&]() {
- switch (static_cast<eMeshWrapperType>(me->runtime.wrapper_type)) {
+ switch (static_cast<eMeshWrapperType>(me->runtime->wrapper_type)) {
case ME_WRAPPER_TYPE_MDATA:
case ME_WRAPPER_TYPE_SUBD: {
break; /* Quiet warning. */
@@ -117,10 +114,10 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *me)
me->totloop = 0;
BLI_assert(me->edit_mesh != nullptr);
- BLI_assert(me->runtime.edit_data != nullptr);
+ BLI_assert(me->runtime->edit_data != nullptr);
BMEditMesh *em = me->edit_mesh;
- BM_mesh_bm_to_me_for_eval(em->bm, me, &me->runtime.cd_mask_extra);
+ BM_mesh_bm_to_me_for_eval(em->bm, me, &me->runtime->cd_mask_extra);
/* Adding original index layers assumes that all BMesh mesh wrappers are created from
* original edit mode meshes (the only case where adding original indices makes sense).
@@ -132,32 +129,30 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *me)
* harmful. */
BKE_mesh_ensure_default_orig_index_customdata_no_check(me);
- EditMeshData *edit_data = me->runtime.edit_data;
+ EditMeshData *edit_data = me->runtime->edit_data;
if (edit_data->vertexCos) {
BKE_mesh_vert_coords_apply(me, edit_data->vertexCos);
- me->runtime.is_original_bmesh = false;
+ me->runtime->is_original_bmesh = false;
}
break;
}
}
- if (me->runtime.wrapper_type_finalize) {
- BKE_mesh_wrapper_deferred_finalize_mdata(me, &me->runtime.cd_mask_extra);
+ if (me->runtime->wrapper_type_finalize) {
+ BKE_mesh_wrapper_deferred_finalize_mdata(me, &me->runtime->cd_mask_extra);
}
/* Keep type assignment last, so that read-only access only uses the mdata code paths after all
* the underlying data has been initialized. */
- me->runtime.wrapper_type = ME_WRAPPER_TYPE_MDATA;
+ me->runtime->wrapper_type = ME_WRAPPER_TYPE_MDATA;
});
-
- BLI_mutex_unlock(mesh_eval_mutex);
}
bool BKE_mesh_wrapper_minmax(const Mesh *me, float min[3], float max[3])
{
- switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ switch (me->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH:
- return BKE_editmesh_cache_calc_minmax(me->edit_mesh, me->runtime.edit_data, min, max);
+ return BKE_editmesh_cache_calc_minmax(me->edit_mesh, me->runtime->edit_data, min, max);
case ME_WRAPPER_TYPE_MDATA:
case ME_WRAPPER_TYPE_SUBD:
return BKE_mesh_minmax(me, min, max);
@@ -174,11 +169,11 @@ void BKE_mesh_wrapper_vert_coords_copy(const Mesh *me,
float (*vert_coords)[3],
int vert_coords_len)
{
- switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ switch (me->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH: {
BMesh *bm = me->edit_mesh->bm;
BLI_assert(vert_coords_len <= bm->totvert);
- EditMeshData *edit_data = me->runtime.edit_data;
+ EditMeshData *edit_data = me->runtime->edit_data;
if (edit_data->vertexCos != nullptr) {
for (int i = 0; i < vert_coords_len; i++) {
copy_v3_v3(vert_coords[i], edit_data->vertexCos[i]);
@@ -212,11 +207,11 @@ void BKE_mesh_wrapper_vert_coords_copy_with_mat4(const Mesh *me,
int vert_coords_len,
const float mat[4][4])
{
- switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ switch (me->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH: {
BMesh *bm = me->edit_mesh->bm;
BLI_assert(vert_coords_len == bm->totvert);
- EditMeshData *edit_data = me->runtime.edit_data;
+ EditMeshData *edit_data = me->runtime->edit_data;
if (edit_data->vertexCos != nullptr) {
for (int i = 0; i < vert_coords_len; i++) {
mul_v3_m4v3(vert_coords[i], mat, edit_data->vertexCos[i]);
@@ -253,7 +248,7 @@ void BKE_mesh_wrapper_vert_coords_copy_with_mat4(const Mesh *me,
int BKE_mesh_wrapper_vert_len(const Mesh *me)
{
- switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ switch (me->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH:
return me->edit_mesh->bm->totvert;
case ME_WRAPPER_TYPE_MDATA:
@@ -266,7 +261,7 @@ int BKE_mesh_wrapper_vert_len(const Mesh *me)
int BKE_mesh_wrapper_edge_len(const Mesh *me)
{
- switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ switch (me->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH:
return me->edit_mesh->bm->totedge;
case ME_WRAPPER_TYPE_MDATA:
@@ -279,7 +274,7 @@ int BKE_mesh_wrapper_edge_len(const Mesh *me)
int BKE_mesh_wrapper_loop_len(const Mesh *me)
{
- switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ switch (me->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH:
return me->edit_mesh->bm->totloop;
case ME_WRAPPER_TYPE_MDATA:
@@ -292,7 +287,7 @@ int BKE_mesh_wrapper_loop_len(const Mesh *me)
int BKE_mesh_wrapper_poly_len(const Mesh *me)
{
- switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ switch (me->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH:
return me->edit_mesh->bm->totface;
case ME_WRAPPER_TYPE_MDATA:
@@ -311,7 +306,7 @@ int BKE_mesh_wrapper_poly_len(const Mesh *me)
static Mesh *mesh_wrapper_ensure_subdivision(Mesh *me)
{
- SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)me->runtime.subsurf_runtime_data;
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)me->runtime->subsurf_runtime_data;
if (runtime_data == nullptr || runtime_data->settings.level == 0) {
return me;
}
@@ -359,24 +354,22 @@ static Mesh *mesh_wrapper_ensure_subdivision(Mesh *me)
}
if (subdiv_mesh != me) {
- if (me->runtime.mesh_eval != nullptr) {
- BKE_id_free(nullptr, me->runtime.mesh_eval);
+ if (me->runtime->mesh_eval != nullptr) {
+ BKE_id_free(nullptr, me->runtime->mesh_eval);
}
- me->runtime.mesh_eval = subdiv_mesh;
- me->runtime.wrapper_type = ME_WRAPPER_TYPE_SUBD;
+ me->runtime->mesh_eval = subdiv_mesh;
+ me->runtime->wrapper_type = ME_WRAPPER_TYPE_SUBD;
}
- return me->runtime.mesh_eval;
+ return me->runtime->mesh_eval;
}
Mesh *BKE_mesh_wrapper_ensure_subdivision(Mesh *me)
{
- ThreadMutex *mesh_eval_mutex = (ThreadMutex *)me->runtime.eval_mutex;
- BLI_mutex_lock(mesh_eval_mutex);
+ std::lock_guard lock{me->runtime->eval_mutex};
- if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_SUBD) {
- BLI_mutex_unlock(mesh_eval_mutex);
- return me->runtime.mesh_eval;
+ if (me->runtime->wrapper_type == ME_WRAPPER_TYPE_SUBD) {
+ return me->runtime->mesh_eval;
}
Mesh *result;
@@ -384,7 +377,6 @@ Mesh *BKE_mesh_wrapper_ensure_subdivision(Mesh *me)
/* Must isolate multithreaded tasks while holding a mutex lock. */
blender::threading::isolate_task([&]() { result = mesh_wrapper_ensure_subdivision(me); });
- BLI_mutex_unlock(mesh_eval_mutex);
return result;
}
diff --git a/source/blender/blenkernel/intern/modifier.cc b/source/blender/blenkernel/intern/modifier.cc
index 2eb8ef70a4d..92a7c778b68 100644
--- a/source/blender/blenkernel/intern/modifier.cc
+++ b/source/blender/blenkernel/intern/modifier.cc
@@ -955,7 +955,7 @@ const char *BKE_modifier_path_relbase_from_global(Object *ob)
void BKE_modifier_path_init(char *path, int path_maxlen, const char *name)
{
const char *blendfile_path = BKE_main_blendfile_path_from_global();
- BLI_join_dirfile(path, path_maxlen, blendfile_path[0] ? "//" : BKE_tempdir_session(), name);
+ BLI_path_join(path, path_maxlen, blendfile_path[0] ? "//" : BKE_tempdir_session(), name);
}
/**
@@ -963,9 +963,9 @@ void BKE_modifier_path_init(char *path, int path_maxlen, const char *name)
*/
static void modwrap_dependsOnNormals(Mesh *me)
{
- switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ switch (me->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH: {
- EditMeshData *edit_data = me->runtime.edit_data;
+ EditMeshData *edit_data = me->runtime->edit_data;
if (edit_data->vertexCos) {
/* Note that 'ensure' is acceptable here since these values aren't modified in-place.
* If that changes we'll need to recalculate. */
@@ -993,7 +993,7 @@ struct Mesh *BKE_modifier_modify_mesh(ModifierData *md,
{
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type));
- if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
+ if (me->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) {
if ((mti->flags & eModifierTypeFlag_AcceptsBMesh) == 0) {
BKE_mesh_wrapper_ensure_mdata(me);
}
diff --git a/source/blender/blenkernel/intern/multires.cc b/source/blender/blenkernel/intern/multires.cc
index 61cfe043927..5ff9602650e 100644
--- a/source/blender/blenkernel/intern/multires.cc
+++ b/source/blender/blenkernel/intern/multires.cc
@@ -397,7 +397,7 @@ void multires_mark_as_modified(Depsgraph *depsgraph, Object *object, MultiresMod
* In a longer term maybe special dependency graph tag can help sanitizing this a bit. */
Object *object_eval = DEG_get_evaluated_object(depsgraph, object);
Mesh *mesh = static_cast<Mesh *>(object_eval->data);
- SubdivCCG *subdiv_ccg = mesh->runtime.subdiv_ccg;
+ SubdivCCG *subdiv_ccg = mesh->runtime->subdiv_ccg;
if (subdiv_ccg == nullptr) {
return;
}
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 654eb06a781..8028f990c42 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -2157,6 +2157,38 @@ void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userd
}
}
+bool nodeIsDanglingReroute(const bNodeTree *ntree, const bNode *node)
+{
+ ntree->ensure_topology_cache();
+ BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*ntree));
+ BLI_assert(!ntree->has_available_link_cycle());
+
+ const bNode *iter_node = node;
+ if (!iter_node->is_reroute()) {
+ return false;
+ }
+
+ while (true) {
+ const blender::Span<const bNodeLink *> links =
+ iter_node->input_socket(0).directly_linked_links();
+ BLI_assert(links.size() <= 1);
+ if (links.is_empty()) {
+ return true;
+ }
+ const bNodeLink &link = *links[0];
+ if (!link.is_available()) {
+ return false;
+ }
+ if (link.is_muted()) {
+ return false;
+ }
+ iter_node = link.fromnode;
+ if (!iter_node->is_reroute()) {
+ return false;
+ }
+ }
+}
+
/* ************** Add stuff ********** */
void nodeUniqueName(bNodeTree *ntree, bNode *node)
diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc
index 9417d1afc7e..2d949fb5c65 100644
--- a/source/blender/blenkernel/intern/object.cc
+++ b/source/blender/blenkernel/intern/object.cc
@@ -1691,7 +1691,7 @@ static void object_update_from_subsurf_ccg(Object *object)
if (mesh_eval == nullptr) {
return;
}
- SubdivCCG *subdiv_ccg = mesh_eval->runtime.subdiv_ccg;
+ SubdivCCG *subdiv_ccg = mesh_eval->runtime->subdiv_ccg;
if (subdiv_ccg == nullptr) {
return;
}
@@ -1699,7 +1699,7 @@ static void object_update_from_subsurf_ccg(Object *object)
if (!subdiv_ccg->dirty.coords && !subdiv_ccg->dirty.hidden) {
return;
}
- const int tot_level = mesh_eval->runtime.subdiv_ccg_tot_level;
+ const int tot_level = mesh_eval->runtime->subdiv_ccg_tot_level;
Object *object_orig = DEG_get_original_object(object);
Mesh *mesh_orig = (Mesh *)object_orig->data;
multiresModifier_reshapeFromCCG(tot_level, mesh_orig, subdiv_ccg);
@@ -3218,7 +3218,7 @@ static void give_parvert(Object *par, int nr, float vec[3])
int count = 0;
int numVerts = me_eval->totvert;
- if (em && me_eval->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
+ if (em && me_eval->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) {
numVerts = em->bm->totvert;
if (em->bm->elem_table_dirty & BM_VERT) {
#ifdef VPARENT_THREADING_HACK
@@ -3233,8 +3233,8 @@ static void give_parvert(Object *par, int nr, float vec[3])
#endif
}
if (nr < numVerts) {
- if (me_eval && me_eval->runtime.edit_data && me_eval->runtime.edit_data->vertexCos) {
- add_v3_v3(vec, me_eval->runtime.edit_data->vertexCos[nr]);
+ if (me_eval && me_eval->runtime->edit_data && me_eval->runtime->edit_data->vertexCos) {
+ add_v3_v3(vec, me_eval->runtime->edit_data->vertexCos[nr]);
}
else {
const BMVert *v = BM_vert_at_index(em->bm, nr);
diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc
index 306e508dc83..d43eff6f9b4 100644
--- a/source/blender/blenkernel/intern/object_dupli.cc
+++ b/source/blender/blenkernel/intern/object_dupli.cc
@@ -41,6 +41,7 @@
#include "BKE_geometry_set.hh"
#include "BKE_global.h"
#include "BKE_idprop.h"
+#include "BKE_instances.hh"
#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
@@ -70,6 +71,8 @@ using blender::float3;
using blender::float4x4;
using blender::Span;
using blender::Vector;
+using blender::bke::InstanceReference;
+using blender::bke::Instances;
namespace geo_log = blender::nodes::geo_eval_log;
/* -------------------------------------------------------------------- */
@@ -423,8 +426,8 @@ static const Mesh *mesh_data_from_duplicator_object(Object *ob,
/* Note that this will only show deformation if #eModifierMode_OnCage is enabled.
* We could change this but it matches 2.7x behavior. */
me_eval = BKE_object_get_editmesh_eval_cage(ob);
- if ((me_eval == nullptr) || (me_eval->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH)) {
- EditMeshData *emd = me_eval ? me_eval->runtime.edit_data : nullptr;
+ if ((me_eval == nullptr) || (me_eval->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH)) {
+ EditMeshData *emd = me_eval ? me_eval->runtime->edit_data : nullptr;
/* Only assign edit-mesh in the case we can't use `me_eval`. */
*r_em = em;
@@ -874,8 +877,8 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
}
const bool creates_duplis_for_components = component_index >= 1;
- const InstancesComponent *component = geometry_set.get_component_for_read<InstancesComponent>();
- if (component == nullptr) {
+ const Instances *instances = geometry_set.get_instances_for_read();
+ if (instances == nullptr) {
return;
}
@@ -890,13 +893,13 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
instances_ctx = &new_instances_ctx;
}
- Span<float4x4> instance_offset_matrices = component->instance_transforms();
- Span<int> instance_reference_handles = component->instance_reference_handles();
- Span<int> almost_unique_ids = component->almost_unique_ids();
- Span<InstanceReference> references = component->references();
+ Span<float4x4> instance_offset_matrices = instances->transforms();
+ Span<int> reference_handles = instances->reference_handles();
+ Span<int> almost_unique_ids = instances->almost_unique_ids();
+ Span<InstanceReference> references = instances->references();
for (int64_t i : instance_offset_matrices.index_range()) {
- const InstanceReference &reference = references[instance_reference_handles[i]];
+ const InstanceReference &reference = references[reference_handles[i]];
const int id = almost_unique_ids[i];
const DupliContext *ctx_for_instance = instances_ctx;
diff --git a/source/blender/blenkernel/intern/object_update.cc b/source/blender/blenkernel/intern/object_update.cc
index 5328d956cee..ceef6404bf0 100644
--- a/source/blender/blenkernel/intern/object_update.cc
+++ b/source/blender/blenkernel/intern/object_update.cc
@@ -373,10 +373,8 @@ void BKE_object_select_update(Depsgraph *depsgraph, Object *object)
DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
if (object->type == OB_MESH && !object->runtime.is_data_eval_owned) {
Mesh *mesh_input = (Mesh *)object->runtime.data_orig;
- Mesh_Runtime *mesh_runtime = &mesh_input->runtime;
- BLI_mutex_lock(static_cast<ThreadMutex *>(mesh_runtime->eval_mutex));
+ std::lock_guard lock{mesh_input->runtime->eval_mutex};
BKE_object_data_select_update(depsgraph, static_cast<ID *>(object->data));
- BLI_mutex_unlock(static_cast<ThreadMutex *>(mesh_runtime->eval_mutex));
}
else {
BKE_object_data_select_update(depsgraph, static_cast<ID *>(object->data));
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index 396c3443a73..bcf382b6022 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -1144,7 +1144,7 @@ static void cache_filename(
break;
}
- BLI_join_dirfile(cachepath, sizeof(cachepath), path, fname);
+ BLI_path_join(cachepath, sizeof(cachepath), path, fname);
BKE_image_path_from_imtype(
string, cachepath, relbase, frame, R_IMF_IMTYPE_OPENEXR, true, true, "");
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index 901b42ac0b2..0c9d9f5b048 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -545,7 +545,7 @@ static void unpack_generate_paths(const char *name,
break;
}
if (dir_name) {
- BLI_path_join(r_relpath, relpathlen, "//", dir_name, tempname, NULL);
+ BLI_path_join(r_relpath, relpathlen, "//", dir_name, tempname);
}
}
diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc
index fbb7642c067..13243925b28 100644
--- a/source/blender/blenkernel/intern/paint.cc
+++ b/source/blender/blenkernel/intern/paint.cc
@@ -54,6 +54,7 @@
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
+#include "BKE_scene.h"
#include "BKE_subdiv_ccg.h"
#include "BKE_subsurf.h"
@@ -1743,7 +1744,7 @@ static void sculpt_update_object(
ss->hide_poly = (bool *)CustomData_get_layer_named(&me->pdata, CD_PROP_BOOL, ".hide_poly");
- ss->subdiv_ccg = me_eval->runtime.subdiv_ccg;
+ ss->subdiv_ccg = me_eval->runtime->subdiv_ccg;
PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(depsgraph, ob);
BLI_assert(pbvh == ss->pbvh);
@@ -1785,8 +1786,8 @@ static void sculpt_update_object(
/* If the fully evaluated mesh has the same topology as the deform-only version, use it.
* This matters because crazyspace evaluation is very restrictive and excludes even modifiers
* that simply recompute vertex weights (which can even include Geometry Nodes). */
- if (me_eval_deform->polys().data() == me_eval->polys().data() &&
- me_eval_deform->loops().data() == me_eval->loops().data() &&
+ if (me_eval_deform->totpoly == me_eval->totpoly &&
+ me_eval_deform->totloop == me_eval->totloop &&
me_eval_deform->totvert == me_eval->totvert) {
BKE_sculptsession_free_deformMats(ss);
@@ -1986,7 +1987,10 @@ bool *BKE_sculpt_hide_poly_ensure(Mesh *mesh)
&mesh->pdata, CD_PROP_BOOL, CD_SET_DEFAULT, nullptr, mesh->totpoly, ".hide_poly"));
}
-int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd)
+int BKE_sculpt_mask_layers_ensure(Depsgraph *depsgraph,
+ Main *bmain,
+ Object *ob,
+ MultiresModifierData *mmd)
{
Mesh *me = static_cast<Mesh *>(ob->data);
const Span<MPoly> polys = me->polys();
@@ -2045,6 +2049,9 @@ int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd)
}
/* The evaluated multires CCG must be updated to contain the new data. */
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ if (depsgraph) {
+ BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
+ }
ret |= SCULPT_MASK_LAYER_CALC_LOOP;
}
@@ -2237,7 +2244,8 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect
(void **)subdiv_ccg->grid_faces,
subdiv_ccg->grid_flag_mats,
subdiv_ccg->grid_hidden,
- base_mesh);
+ base_mesh,
+ subdiv_ccg);
pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
pbvh_show_face_sets_set(pbvh, ob->sculpt->show_face_sets);
return pbvh;
@@ -2258,7 +2266,7 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
if (BKE_pbvh_type(pbvh) == PBVH_GRIDS) {
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
Mesh *mesh_eval = static_cast<Mesh *>(object_eval->data);
- SubdivCCG *subdiv_ccg = mesh_eval->runtime.subdiv_ccg;
+ SubdivCCG *subdiv_ccg = mesh_eval->runtime->subdiv_ccg;
if (subdiv_ccg != nullptr) {
BKE_sculpt_bvh_update_from_ccg(pbvh, subdiv_ccg);
}
@@ -2277,8 +2285,8 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
else {
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
Mesh *mesh_eval = static_cast<Mesh *>(object_eval->data);
- if (mesh_eval->runtime.subdiv_ccg != nullptr) {
- pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime.subdiv_ccg, respect_hide);
+ if (mesh_eval->runtime->subdiv_ccg != nullptr) {
+ pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime->subdiv_ccg, respect_hide);
}
else if (ob->type == OB_MESH) {
Mesh *me_eval_deform = object_eval->runtime.mesh_deform_eval;
@@ -2295,11 +2303,15 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
void BKE_sculpt_bvh_update_from_ccg(PBVH *pbvh, SubdivCCG *subdiv_ccg)
{
+ CCGKey key;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+
BKE_pbvh_grids_update(pbvh,
subdiv_ccg->grids,
(void **)subdiv_ccg->grid_faces,
subdiv_ccg->grid_flag_mats,
- subdiv_ccg->grid_hidden);
+ subdiv_ccg->grid_hidden,
+ &key);
}
bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D * /*v3d*/)
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 6d42d344b86..d6dd3cf0dbb 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -60,6 +60,7 @@
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_mesh_legacy_convert.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_particle.h"
@@ -1933,7 +1934,7 @@ int psys_particle_dm_face_lookup(Mesh *mesh_final,
index_mf_to_mpoly_deformed = CustomData_get_layer(&mesh_original->fdata, CD_ORIGINDEX);
}
else {
- BLI_assert(mesh_final->runtime.deformed_only);
+ BLI_assert(BKE_mesh_is_deformed_only(mesh_final));
index_mf_to_mpoly_deformed = index_mf_to_mpoly;
}
BLI_assert(index_mf_to_mpoly_deformed);
@@ -2023,7 +2024,7 @@ static int psys_map_index_on_dm(Mesh *mesh,
return 0;
}
- if (mesh->runtime.deformed_only || index_dmcache == DMCACHE_ISCHILD) {
+ if (BKE_mesh_is_deformed_only(mesh) || index_dmcache == DMCACHE_ISCHILD) {
/* for meshes that are either only deformed or for child particles, the
* index and fw do not require any mapping, so we can directly use it */
if (from == PART_FROM_VERT) {
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 4c56a8a9275..0301b83a043 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -29,6 +29,7 @@
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
#include "BKE_mesh_legacy_convert.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_object.h"
#include "BKE_particle.h"
@@ -899,7 +900,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx,
return 0;
}
- if (!final_mesh->runtime.deformed_only &&
+ if (!BKE_mesh_is_deformed_only(final_mesh) &&
!CustomData_get_layer(&final_mesh->fdata, CD_ORIGINDEX)) {
printf(
"Can't create particles with the current modifier stack, disable destructive modifiers\n");
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index dec874caff4..c72bbe2fd08 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -48,6 +48,7 @@
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_mesh_legacy_convert.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_particle.h"
#include "BKE_bvhutils.h"
@@ -319,7 +320,7 @@ void psys_calc_dmcache(Object *ob, Mesh *mesh_final, Mesh *mesh_original, Partic
PARTICLE_P;
/* CACHE LOCATIONS */
- if (!mesh_final->runtime.deformed_only) {
+ if (!BKE_mesh_is_deformed_only(mesh_final)) {
/* Will use later to speed up subsurf/evaluated mesh. */
LinkNode *node, *nodedmelem, **nodearray;
int totdmelem, totelem, i;
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index b23fe53e80c..98e89b09060 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -39,8 +39,10 @@
#define LEAF_LIMIT 10000
-//#define PERFCNTRS
+/* Uncomment to test that faces are only assigned to one PBVHNode */
+//#define VALIDATE_UNIQUE_NODE_FACES
+//#define PERFCNTRS
#define STACK_FIXED_DEPTH 100
typedef struct PBVHStack {
@@ -422,6 +424,56 @@ static bool leaf_needs_material_split(PBVH *pbvh, int offset, int count)
return false;
}
+static int adjust_partition_faces(PBVH *pbvh, int offset, int mid, int count)
+{
+ int poly = pbvh->looptri[pbvh->prim_indices[mid]].poly;
+
+ /* Scan backwards. */
+ while (mid > offset + 2) { /* First node should have at least 1 primitive */
+ if (pbvh->looptri[pbvh->prim_indices[mid - 1]].poly != poly) {
+ return mid;
+ }
+
+ mid--;
+ }
+
+ /* If that didn't work try scanning forward. */
+ while (mid < pbvh->totprim + count) {
+ if (pbvh->looptri[pbvh->prim_indices[mid]].poly != poly) {
+ break;
+ }
+
+ mid++;
+ }
+
+ return mid;
+}
+
+static int adjust_partition_grids(PBVH *pbvh, int offset, int mid, int count)
+{
+ int poly = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, pbvh->prim_indices[mid]);
+
+ /* Scan backwards. */
+ while (mid > offset + 2) { /* First node should have at least 1 primitive */
+ if (BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, pbvh->prim_indices[mid - 1]) != poly) {
+ return mid;
+ }
+
+ mid--;
+ }
+
+ /* If that didn't work try scanning forward. */
+ while (mid < pbvh->totprim + count) {
+ if (BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, pbvh->prim_indices[mid]) != poly) {
+ break;
+ }
+
+ mid++;
+ }
+
+ return mid;
+}
+
/* Recursively build a node in the tree
*
* vb is the voxel box around all of the primitives contained in
@@ -478,6 +530,13 @@ static void build_sub(PBVH *pbvh, int node_index, BB *cb, BBC *prim_bbc, int off
end = partition_indices_material(pbvh, offset, offset + count - 1);
}
+ if (pbvh->header.type == PBVH_FACES) {
+ end = adjust_partition_faces(pbvh, offset, end, count);
+ }
+ else {
+ end = adjust_partition_grids(pbvh, offset, end, count);
+ }
+
/* Build children */
build_sub(pbvh, pbvh->nodes[node_index].children_offset, NULL, prim_bbc, offset, end - offset);
build_sub(pbvh,
@@ -587,6 +646,73 @@ static void pbvh_draw_args_init(PBVH *pbvh, PBVH_GPU_Args *args, PBVHNode *node)
}
}
+#ifdef VALIDATE_UNIQUE_NODE_FACES
+static void pbvh_validate_node_prims(PBVH *pbvh)
+{
+ int totface = 0;
+
+ if (pbvh->header.type == PBVH_BMESH) {
+ return;
+ }
+
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *node = pbvh->nodes + i;
+
+ if (!(node->flag & PBVH_Leaf)) {
+ continue;
+ }
+
+ for (int j = 0; j < node->totprim; j++) {
+ int poly;
+
+ if (pbvh->header.type == PBVH_FACES) {
+ poly = pbvh->looptri[node->prim_indices[j]].poly;
+ }
+ else {
+ poly = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, node->prim_indices[j]);
+ }
+
+ totface = max_ii(totface, poly + 1);
+ }
+ }
+
+ int *facemap = (int *)MEM_malloc_arrayN(totface, sizeof(*facemap), __func__);
+
+ for (int i = 0; i < totface; i++) {
+ facemap[i] = -1;
+ }
+
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *node = pbvh->nodes + i;
+
+ if (!(node->flag & PBVH_Leaf)) {
+ continue;
+ }
+
+ for (int j = 0; j < node->totprim; j++) {
+ int poly;
+
+ if (pbvh->header.type == PBVH_FACES) {
+ poly = pbvh->looptri[node->prim_indices[j]].poly;
+ }
+ else {
+ poly = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, node->prim_indices[j]);
+ }
+
+ if (facemap[poly] != -1 && facemap[poly] != i) {
+ printf("%s: error: face spanned multiple nodes (old: %d new: %d)\n",
+ __func__,
+ facemap[poly],
+ i);
+ }
+
+ facemap[poly] = i;
+ }
+ }
+ MEM_SAFE_FREE(facemap);
+}
+#endif
+
void BKE_pbvh_build_mesh(PBVH *pbvh,
Mesh *mesh,
const MPoly *mpoly,
@@ -645,6 +771,32 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
BB_expand(&cb, bbc->bcentroid);
}
+ /* Ensure all primitives belonging to the same base face
+ * have the same bounds. This is needed to prevent them
+ * from being swapped away from each other inside the partition
+ * array.
+ */
+ for (int i = 0; i < looptri_num; i++) {
+ const MLoopTri *lt = &looptri[i];
+ int poly = lt->poly;
+ BBC *bbc = prim_bbc + i;
+ int j = i + 1;
+
+ while (j < looptri_num && looptri[j].poly == poly) {
+ BBC *bbc2 = prim_bbc + j;
+
+ BB_expand((BB *)bbc, bbc2->bmin);
+ BB_expand((BB *)bbc, bbc2->bmax);
+ j++;
+ }
+
+ j = i + 1;
+ while (j < looptri_num && looptri[j].poly == poly) {
+ prim_bbc[j] = prim_bbc[i];
+ j++;
+ }
+ }
+
if (looptri_num) {
pbvh_build(pbvh, &cb, prim_bbc, looptri_num);
}
@@ -655,6 +807,10 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
memset(pbvh->vert_bitmap, 0, sizeof(bool) * totvert);
BKE_pbvh_update_active_vcol(pbvh, mesh);
+
+#ifdef VALIDATE_UNIQUE_NODE_FACES
+ pbvh_validate_node_prims(pbvh);
+#endif
}
void BKE_pbvh_build_grids(PBVH *pbvh,
@@ -664,7 +820,8 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
void **gridfaces,
DMFlagMat *flagmats,
BLI_bitmap **grid_hidden,
- Mesh *me)
+ Mesh *me,
+ SubdivCCG *subdiv_ccg)
{
const int gridsize = key->grid_size;
@@ -675,6 +832,7 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
pbvh->totgrid = totgrid;
pbvh->gridkey = *key;
pbvh->grid_hidden = grid_hidden;
+ pbvh->subdiv_ccg = subdiv_ccg;
pbvh->leaf_limit = max_ii(LEAF_LIMIT / (gridsize * gridsize), 1);
/* We need the base mesh attribute layout for PBVH draw. */
@@ -706,11 +864,40 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
BB_expand(&cb, bbc->bcentroid);
}
+ /* Ensure all primitives belonging to the same base face
+ * have the same bounds. This is needed to prevent them
+ * from being swapped away from each other inside the partition
+ * array.
+ */
+ for (int i = 0; i < totgrid; i++) {
+ int poly = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, i);
+
+ BBC *bbc = prim_bbc + i;
+ int j = i + 1;
+
+ while (j < totgrid && BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, j) == poly) {
+ BBC *bbc2 = prim_bbc + j;
+
+ BB_expand((BB *)bbc, bbc2->bmin);
+ BB_expand((BB *)bbc, bbc2->bmax);
+ j++;
+ }
+
+ j = i + 1;
+ while (j < totgrid && BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, j) == poly) {
+ prim_bbc[j] = prim_bbc[i];
+ j++;
+ }
+ }
+
if (totgrid) {
pbvh_build(pbvh, &cb, prim_bbc, totgrid);
}
MEM_freeN(prim_bbc);
+#ifdef VALIDATE_UNIQUE_NODE_FACES
+ pbvh_validate_node_prims(pbvh);
+#endif
}
PBVH *BKE_pbvh_new(PBVHType type)
@@ -719,6 +906,11 @@ PBVH *BKE_pbvh_new(PBVHType type)
pbvh->respect_hide = true;
pbvh->draw_cache_invalid = true;
pbvh->header.type = type;
+
+ /* Initialize this to true, instead of waiting for a draw engine
+ * to set it. Prevents a crash in draw manager instancing code.
+ */
+ pbvh->is_drawing = true;
return pbvh;
}
@@ -2872,9 +3064,14 @@ void BKE_pbvh_draw_debug_cb(PBVH *pbvh,
}
}
-void BKE_pbvh_grids_update(
- PBVH *pbvh, CCGElem **grids, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap **grid_hidden)
+void BKE_pbvh_grids_update(PBVH *pbvh,
+ CCGElem **grids,
+ void **gridfaces,
+ DMFlagMat *flagmats,
+ BLI_bitmap **grid_hidden,
+ CCGKey *key)
{
+ pbvh->gridkey = *key;
pbvh->grids = grids;
pbvh->gridfaces = gridfaces;
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 5ec69f9bc45..ac98bed2cf0 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -2640,7 +2640,7 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, uint cfra)
if (STREQLEN(filepath, de->d_name, len)) { /* Do we have the right prefix. */
if (mode == PTCACHE_CLEAR_ALL) {
pid->cache->last_exact = MIN2(pid->cache->startframe, 0);
- BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name);
+ BLI_path_join(path_full, sizeof(path_full), path, de->d_name);
BLI_delete(path_full, false, false);
}
else {
@@ -2650,7 +2650,7 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, uint cfra)
if (frame != -1) {
if ((mode == PTCACHE_CLEAR_BEFORE && frame < cfra) ||
(mode == PTCACHE_CLEAR_AFTER && frame > cfra)) {
- BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name);
+ BLI_path_join(path_full, sizeof(path_full), path, de->d_name);
BLI_delete(path_full, false, false);
if (pid->cache->cached_frames && frame >= sta && frame <= end) {
pid->cache->cached_frames[frame - sta] = 0;
@@ -3524,7 +3524,7 @@ void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const c
const int frame = ptcache_frame_from_filename(de->d_name, ext);
if (frame != -1) {
- BLI_join_dirfile(old_path_full, sizeof(old_path_full), path, de->d_name);
+ BLI_path_join(old_path_full, sizeof(old_path_full), path, de->d_name);
ptcache_filepath(pid, new_path_full, frame, true, true);
BLI_rename(old_path_full, new_path_full);
}
diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc
index c73bbb91965..119daccce20 100644
--- a/source/blender/blenkernel/intern/pointcloud.cc
+++ b/source/blender/blenkernel/intern/pointcloud.cc
@@ -239,12 +239,6 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint)
nullptr, ID_PT, BKE_idtype_idcode_to_name(ID_PT), LIB_ID_CREATE_LOCALIZE));
pointcloud_init_data(&pointcloud->id);
- CustomData_add_layer_named(&pointcloud->pdata,
- CD_PROP_FLOAT,
- CD_SET_DEFAULT,
- nullptr,
- pointcloud->totpoint,
- POINTCLOUD_ATTR_RADIUS);
CustomData_realloc(&pointcloud->pdata, 0, totpoint);
pointcloud->totpoint = totpoint;
diff --git a/source/blender/blenkernel/intern/preferences.c b/source/blender/blenkernel/intern/preferences.c
index b2e795901fb..dd76f9eddc1 100644
--- a/source/blender/blenkernel/intern/preferences.c
+++ b/source/blender/blenkernel/intern/preferences.c
@@ -115,8 +115,7 @@ void BKE_preferences_asset_library_default_add(UserDef *userdef)
userdef, DATA_(BKE_PREFS_ASSET_LIBRARY_DEFAULT_NAME), NULL);
/* Add new "Default" library under '[doc_path]/Blender/Assets'. */
- BLI_path_join(
- library->path, sizeof(library->path), documents_path, N_("Blender"), N_("Assets"), NULL);
+ BLI_path_join(library->path, sizeof(library->path), documents_path, N_("Blender"), N_("Assets"));
}
/** \} */
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 6b4cddb05f2..ffc6bc8d7a3 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -404,7 +404,7 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob)
const MVert *mvert = BKE_mesh_verts(mesh);
totvert = mesh->totvert;
looptri = BKE_mesh_runtime_looptri_ensure(mesh);
- tottri = mesh->runtime.looptris.len;
+ tottri = BKE_mesh_runtime_looptri_len(mesh);
const MLoop *mloop = BKE_mesh_loops(mesh);
/* sanity checking - potential case when no data will be present */
@@ -679,7 +679,7 @@ void BKE_rigidbody_calc_volume(Object *ob, float *r_vol)
const MVert *mvert = BKE_mesh_verts(mesh);
totvert = mesh->totvert;
lt = BKE_mesh_runtime_looptri_ensure(mesh);
- tottri = mesh->runtime.looptris.len;
+ tottri = BKE_mesh_runtime_looptri_len(mesh);
const MLoop *mloop = BKE_mesh_loops(mesh);
if (totvert > 0 && tottri > 0) {
@@ -753,7 +753,7 @@ void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3])
const MVert *mvert = BKE_mesh_verts(mesh);
totvert = mesh->totvert;
looptri = BKE_mesh_runtime_looptri_ensure(mesh);
- tottri = mesh->runtime.looptris.len;
+ tottri = BKE_mesh_runtime_looptri_len(mesh);
const MLoop *mloop = BKE_mesh_loops(mesh);
if (totvert > 0 && tottri > 0) {
diff --git a/source/blender/blenkernel/intern/scene.cc b/source/blender/blenkernel/intern/scene.cc
index fc47fb71bf3..bd26075f81f 100644
--- a/source/blender/blenkernel/intern/scene.cc
+++ b/source/blender/blenkernel/intern/scene.cc
@@ -280,6 +280,9 @@ static void scene_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
}
/* View Layers */
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene_src->view_layers) {
+ BKE_view_layer_synced_ensure(scene_src, view_layer);
+ }
BLI_duplicatelist(&scene_dst->view_layers, &scene_src->view_layers);
for (ViewLayer *view_layer_src = static_cast<ViewLayer *>(scene_src->view_layers.first),
*view_layer_dst = static_cast<ViewLayer *>(scene_dst->view_layers.first);
diff --git a/source/blender/blenkernel/intern/shrinkwrap.cc b/source/blender/blenkernel/intern/shrinkwrap.cc
index 703b012d170..65226a5db9d 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.cc
+++ b/source/blender/blenkernel/intern/shrinkwrap.cc
@@ -140,7 +140,7 @@ bool BKE_shrinkwrap_init_tree(
}
if (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) {
- data->boundary = mesh->runtime.shrinkwrap_data;
+ data->boundary = mesh->runtime->shrinkwrap_data;
}
return true;
@@ -153,7 +153,7 @@ void BKE_shrinkwrap_free_tree(ShrinkwrapTreeData *data)
void BKE_shrinkwrap_discard_boundary_data(Mesh *mesh)
{
- ShrinkwrapBoundaryData *data = mesh->runtime.shrinkwrap_data;
+ ShrinkwrapBoundaryData *data = mesh->runtime->shrinkwrap_data;
if (data != nullptr) {
MEM_freeN((void *)data->edge_is_boundary);
@@ -164,7 +164,7 @@ void BKE_shrinkwrap_discard_boundary_data(Mesh *mesh)
MEM_freeN(data);
}
- mesh->runtime.shrinkwrap_data = nullptr;
+ mesh->runtime->shrinkwrap_data = nullptr;
}
/* Accumulate edge for average boundary edge direction. */
@@ -327,7 +327,7 @@ void BKE_shrinkwrap_compute_boundary_data(Mesh *mesh)
{
BKE_shrinkwrap_discard_boundary_data(mesh);
- mesh->runtime.shrinkwrap_data = shrinkwrap_build_boundary_data(mesh);
+ mesh->runtime->shrinkwrap_data = shrinkwrap_build_boundary_data(mesh);
}
/**
diff --git a/source/blender/blenkernel/intern/subdiv_ccg.cc b/source/blender/blenkernel/intern/subdiv_ccg.cc
index 8ccf2c9cec5..bf09be444b1 100644
--- a/source/blender/blenkernel/intern/subdiv_ccg.cc
+++ b/source/blender/blenkernel/intern/subdiv_ccg.cc
@@ -615,7 +615,7 @@ Mesh *BKE_subdiv_to_ccg_mesh(Subdiv *subdiv,
return nullptr;
}
Mesh *result = BKE_mesh_new_nomain_from_template(coarse_mesh, 0, 0, 0, 0, 0);
- result->runtime.subdiv_ccg = subdiv_ccg;
+ result->runtime->subdiv_ccg = subdiv_ccg;
return result;
}
diff --git a/source/blender/blenkernel/intern/subdiv_mesh.cc b/source/blender/blenkernel/intern/subdiv_mesh.cc
index 00183ea90c2..3b97c1f5e68 100644
--- a/source/blender/blenkernel/intern/subdiv_mesh.cc
+++ b/source/blender/blenkernel/intern/subdiv_mesh.cc
@@ -528,9 +528,9 @@ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_contex
subdiv_context->coarse_mesh, num_vertices, num_edges, 0, num_loops, num_polygons, mask);
subdiv_mesh_ctx_cache_custom_data_layers(subdiv_context);
subdiv_mesh_prepare_accumulator(subdiv_context, num_vertices);
- MEM_SAFE_FREE(subdiv_context->subdiv_mesh->runtime.subsurf_face_dot_tags);
- subdiv_context->subdiv_mesh->runtime.subsurf_face_dot_tags = BLI_BITMAP_NEW(num_vertices,
- __func__);
+ MEM_SAFE_FREE(subdiv_context->subdiv_mesh->runtime->subsurf_face_dot_tags);
+ subdiv_context->subdiv_mesh->runtime->subsurf_face_dot_tags = BLI_BITMAP_NEW(num_vertices,
+ __func__);
return true;
}
@@ -595,7 +595,7 @@ static void evaluate_vertex_and_apply_displacement_copy(const SubdivMeshContext
/* Evaluate undeformed texture coordinate. */
subdiv_vertex_orco_evaluate(ctx, ptex_face_index, u, v, subdiv_vertex_index);
/* Remove face-dot flag. This can happen if there is more than one subsurf modifier. */
- BLI_BITMAP_DISABLE(ctx->subdiv_mesh->runtime.subsurf_face_dot_tags, subdiv_vertex_index);
+ BLI_BITMAP_DISABLE(ctx->subdiv_mesh->runtime->subsurf_face_dot_tags, subdiv_vertex_index);
}
static void evaluate_vertex_and_apply_displacement_interpolate(
@@ -753,7 +753,7 @@ static void subdiv_mesh_tag_center_vertex(const MPoly *coarse_poly,
Mesh *subdiv_mesh)
{
if (subdiv_mesh_is_center_vertex(coarse_poly, u, v)) {
- BLI_BITMAP_ENABLE(subdiv_mesh->runtime.subsurf_face_dot_tags, subdiv_vertex_index);
+ BLI_BITMAP_ENABLE(subdiv_mesh->runtime->subsurf_face_dot_tags, subdiv_vertex_index);
}
}
diff --git a/source/blender/blenkernel/intern/subdiv_modifier.cc b/source/blender/blenkernel/intern/subdiv_modifier.cc
index a5529e9b8fa..84b772db045 100644
--- a/source/blender/blenkernel/intern/subdiv_modifier.cc
+++ b/source/blender/blenkernel/intern/subdiv_modifier.cc
@@ -11,6 +11,7 @@
#include "DNA_scene_types.h"
#include "DNA_userdef_types.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_subdiv.h"
@@ -143,7 +144,7 @@ bool BKE_subsurf_modifier_can_do_gpu_subdiv(const Scene *scene,
bool BKE_subsurf_modifier_has_gpu_subdiv(const Mesh *mesh)
{
- SubsurfRuntimeData *runtime_data = mesh->runtime.subsurf_runtime_data;
+ SubsurfRuntimeData *runtime_data = mesh->runtime->subsurf_runtime_data;
return runtime_data && runtime_data->has_gpu_subdiv;
}