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:
Diffstat (limited to 'source/blender/blenkernel/intern')
-rw-r--r--source/blender/blenkernel/intern/attribute.c4
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc1080
-rw-r--r--source/blender/blenkernel/intern/fluid.c2
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc554
-rw-r--r--source/blender/blenkernel/intern/hair.c4
-rw-r--r--source/blender/blenkernel/intern/lib_remap.c2
-rw-r--r--source/blender/blenkernel/intern/node.c49
-rw-r--r--source/blender/blenkernel/intern/object.c17
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c48
-rw-r--r--source/blender/blenkernel/intern/pointcache.c3
-rw-r--r--source/blender/blenkernel/intern/pointcloud.cc125
-rw-r--r--source/blender/blenkernel/intern/simulation.cc4
12 files changed, 1809 insertions, 83 deletions
diff --git a/source/blender/blenkernel/intern/attribute.c b/source/blender/blenkernel/intern/attribute.c
index 9ad73133f9e..d8fd3a19303 100644
--- a/source/blender/blenkernel/intern/attribute.c
+++ b/source/blender/blenkernel/intern/attribute.c
@@ -63,8 +63,8 @@ static void get_domains(ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
}
case ID_ME: {
Mesh *mesh = (Mesh *)id;
- info[ATTR_DOMAIN_VERTEX].customdata = &mesh->vdata;
- info[ATTR_DOMAIN_VERTEX].length = mesh->totvert;
+ info[ATTR_DOMAIN_POINT].customdata = &mesh->vdata;
+ info[ATTR_DOMAIN_POINT].length = mesh->totvert;
info[ATTR_DOMAIN_EDGE].customdata = &mesh->edata;
info[ATTR_DOMAIN_EDGE].length = mesh->totedge;
info[ATTR_DOMAIN_CORNER].customdata = &mesh->ldata;
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
new file mode 100644
index 00000000000..2345c834be4
--- /dev/null
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -0,0 +1,1080 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <utility>
+
+#include "BKE_attribute_access.hh"
+#include "BKE_customdata.h"
+#include "BKE_deform.h"
+#include "BKE_geometry_set.hh"
+#include "BKE_mesh.h"
+#include "BKE_pointcloud.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_pointcloud_types.h"
+
+#include "BLI_color.hh"
+#include "BLI_float2.hh"
+#include "BLI_span.hh"
+
+#include "CLG_log.h"
+
+#include "NOD_node_tree_multi_function.hh"
+
+static CLG_LogRef LOG = {"bke.attribute_access"};
+
+using blender::float3;
+using blender::Set;
+using blender::StringRef;
+using blender::bke::ReadAttributePtr;
+using blender::bke::WriteAttributePtr;
+
+/* Can't include BKE_object_deform.h right now, due to an enum forward declaration. */
+extern "C" MDeformVert *BKE_object_defgroup_data_create(ID *id);
+
+namespace blender::bke {
+
+/* -------------------------------------------------------------------- */
+/** \name Attribute Accessor implementations
+ * \{ */
+
+ReadAttribute::~ReadAttribute()
+{
+ if (array_is_temporary_ && array_buffer_ != nullptr) {
+ cpp_type_.destruct_n(array_buffer_, size_);
+ MEM_freeN(array_buffer_);
+ }
+}
+
+fn::GSpan ReadAttribute::get_span() const
+{
+ if (size_ == 0) {
+ return fn::GSpan(cpp_type_);
+ }
+ if (array_buffer_ == nullptr) {
+ std::lock_guard lock{span_mutex_};
+ if (array_buffer_ == nullptr) {
+ this->initialize_span();
+ }
+ }
+ return fn::GSpan(cpp_type_, array_buffer_, size_);
+}
+
+void ReadAttribute::initialize_span() const
+{
+ const int element_size = cpp_type_.size();
+ array_buffer_ = MEM_mallocN_aligned(size_ * element_size, cpp_type_.alignment(), __func__);
+ array_is_temporary_ = true;
+ for (const int i : IndexRange(size_)) {
+ this->get_internal(i, POINTER_OFFSET(array_buffer_, i * element_size));
+ }
+}
+
+WriteAttribute::~WriteAttribute()
+{
+ if (array_should_be_applied_) {
+ CLOG_ERROR(&LOG, "Forgot to call apply_span.");
+ }
+ if (array_is_temporary_ && array_buffer_ != nullptr) {
+ cpp_type_.destruct_n(array_buffer_, size_);
+ MEM_freeN(array_buffer_);
+ }
+}
+
+/**
+ * Get a mutable span that can be modified. When all modifications to the attribute are done,
+ * #apply_span_if_necessary should be called.
+ */
+fn::GMutableSpan WriteAttribute::get_span()
+{
+ if (size_ == 0) {
+ return fn::GMutableSpan(cpp_type_);
+ }
+ if (array_buffer_ == nullptr) {
+ this->initialize_span();
+ }
+ array_should_be_applied_ = true;
+ return fn::GMutableSpan(cpp_type_, array_buffer_, size_);
+}
+
+void WriteAttribute::initialize_span()
+{
+ array_buffer_ = MEM_mallocN_aligned(cpp_type_.size() * size_, cpp_type_.alignment(), __func__);
+ array_is_temporary_ = true;
+ /* This does nothing for trivial types, but is necessary for general correctness. */
+ cpp_type_.construct_default_n(array_buffer_, size_);
+}
+
+void WriteAttribute::apply_span()
+{
+ this->apply_span_if_necessary();
+ array_should_be_applied_ = false;
+}
+
+void WriteAttribute::apply_span_if_necessary()
+{
+ /* Only works when the span has been initialized beforehand. */
+ BLI_assert(array_buffer_ != nullptr);
+
+ const int element_size = cpp_type_.size();
+ for (const int i : IndexRange(size_)) {
+ this->set_internal(i, POINTER_OFFSET(array_buffer_, i * element_size));
+ }
+}
+
+class VertexWeightWriteAttribute final : public WriteAttribute {
+ private:
+ MDeformVert *dverts_;
+ const int dvert_index_;
+
+ public:
+ VertexWeightWriteAttribute(MDeformVert *dverts, const int totvert, const int dvert_index)
+ : WriteAttribute(ATTR_DOMAIN_POINT, CPPType::get<float>(), totvert),
+ dverts_(dverts),
+ dvert_index_(dvert_index)
+ {
+ }
+
+ void get_internal(const int64_t index, void *r_value) const override
+ {
+ get_internal(dverts_, dvert_index_, index, r_value);
+ }
+
+ void set_internal(const int64_t index, const void *value) override
+ {
+ MDeformWeight *weight = BKE_defvert_ensure_index(&dverts_[index], dvert_index_);
+ weight->weight = *reinterpret_cast<const float *>(value);
+ }
+
+ static void get_internal(const MDeformVert *dverts,
+ const int dvert_index,
+ const int64_t index,
+ void *r_value)
+ {
+ if (dverts == nullptr) {
+ *(float *)r_value = 0.0f;
+ return;
+ }
+ const MDeformVert &dvert = dverts[index];
+ for (const MDeformWeight &weight : Span(dvert.dw, dvert.totweight)) {
+ if (weight.def_nr == dvert_index) {
+ *(float *)r_value = weight.weight;
+ return;
+ }
+ }
+ *(float *)r_value = 0.0f;
+ }
+};
+
+class VertexWeightReadAttribute final : public ReadAttribute {
+ private:
+ const MDeformVert *dverts_;
+ const int dvert_index_;
+
+ public:
+ VertexWeightReadAttribute(const MDeformVert *dverts, const int totvert, const int dvert_index)
+ : ReadAttribute(ATTR_DOMAIN_POINT, CPPType::get<float>(), totvert),
+ dverts_(dverts),
+ dvert_index_(dvert_index)
+ {
+ }
+
+ void get_internal(const int64_t index, void *r_value) const override
+ {
+ VertexWeightWriteAttribute::get_internal(dverts_, dvert_index_, index, r_value);
+ }
+};
+
+template<typename T> class ArrayWriteAttribute final : public WriteAttribute {
+ private:
+ MutableSpan<T> data_;
+
+ public:
+ ArrayWriteAttribute(AttributeDomain domain, MutableSpan<T> data)
+ : WriteAttribute(domain, CPPType::get<T>(), data.size()), data_(data)
+ {
+ }
+
+ void get_internal(const int64_t index, void *r_value) const override
+ {
+ new (r_value) T(data_[index]);
+ }
+
+ void set_internal(const int64_t index, const void *value) override
+ {
+ data_[index] = *reinterpret_cast<const T *>(value);
+ }
+
+ void initialize_span() override
+ {
+ array_buffer_ = data_.data();
+ array_is_temporary_ = false;
+ }
+
+ void apply_span_if_necessary() override
+ {
+ /* Do nothing, because the span contains the attribute itself already. */
+ }
+};
+
+template<typename T> class ArrayReadAttribute final : public ReadAttribute {
+ private:
+ Span<T> data_;
+
+ public:
+ ArrayReadAttribute(AttributeDomain domain, Span<T> data)
+ : ReadAttribute(domain, CPPType::get<T>(), data.size()), data_(data)
+ {
+ }
+
+ void get_internal(const int64_t index, void *r_value) const override
+ {
+ new (r_value) T(data_[index]);
+ }
+
+ void initialize_span() const override
+ {
+ /* The data will not be modified, so this const_cast is fine. */
+ array_buffer_ = const_cast<T *>(data_.data());
+ array_is_temporary_ = false;
+ }
+};
+
+template<typename StructT, typename ElemT, typename GetFuncT, typename SetFuncT>
+class DerivedArrayWriteAttribute final : public WriteAttribute {
+ private:
+ MutableSpan<StructT> data_;
+ GetFuncT get_function_;
+ SetFuncT set_function_;
+
+ public:
+ DerivedArrayWriteAttribute(AttributeDomain domain,
+ MutableSpan<StructT> data,
+ GetFuncT get_function,
+ SetFuncT set_function)
+ : WriteAttribute(domain, CPPType::get<ElemT>(), data.size()),
+ data_(data),
+ get_function_(std::move(get_function)),
+ set_function_(std::move(set_function))
+ {
+ }
+
+ void get_internal(const int64_t index, void *r_value) const override
+ {
+ const StructT &struct_value = data_[index];
+ const ElemT value = get_function_(struct_value);
+ new (r_value) ElemT(value);
+ }
+
+ void set_internal(const int64_t index, const void *value) override
+ {
+ StructT &struct_value = data_[index];
+ const ElemT &typed_value = *reinterpret_cast<const ElemT *>(value);
+ set_function_(struct_value, typed_value);
+ }
+};
+
+template<typename StructT, typename ElemT, typename GetFuncT>
+class DerivedArrayReadAttribute final : public ReadAttribute {
+ private:
+ Span<StructT> data_;
+ GetFuncT get_function_;
+
+ public:
+ DerivedArrayReadAttribute(AttributeDomain domain, Span<StructT> data, GetFuncT get_function)
+ : ReadAttribute(domain, CPPType::get<ElemT>(), data.size()),
+ data_(data),
+ get_function_(std::move(get_function))
+ {
+ }
+
+ void get_internal(const int64_t index, void *r_value) const override
+ {
+ const StructT &struct_value = data_[index];
+ const ElemT value = get_function_(struct_value);
+ new (r_value) ElemT(value);
+ }
+};
+
+class ConstantReadAttribute final : public ReadAttribute {
+ private:
+ void *value_;
+
+ public:
+ ConstantReadAttribute(AttributeDomain domain,
+ const int64_t size,
+ const CPPType &type,
+ const void *value)
+ : ReadAttribute(domain, type, size)
+ {
+ value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__);
+ type.copy_to_uninitialized(value, value_);
+ }
+
+ ~ConstantReadAttribute()
+ {
+ this->cpp_type_.destruct(value_);
+ MEM_freeN(value_);
+ }
+
+ void get_internal(const int64_t UNUSED(index), void *r_value) const override
+ {
+ this->cpp_type_.copy_to_uninitialized(value_, r_value);
+ }
+
+ void initialize_span() const override
+ {
+ const int element_size = cpp_type_.size();
+ array_buffer_ = MEM_mallocN_aligned(size_ * element_size, cpp_type_.alignment(), __func__);
+ array_is_temporary_ = true;
+ cpp_type_.fill_uninitialized(value_, array_buffer_, size_);
+ }
+};
+
+class ConvertedReadAttribute final : public ReadAttribute {
+ private:
+ const CPPType &from_type_;
+ const CPPType &to_type_;
+ ReadAttributePtr base_attribute_;
+ const nodes::DataTypeConversions &conversions_;
+
+ static constexpr int MaxValueSize = 64;
+ static constexpr int MaxValueAlignment = 64;
+
+ public:
+ ConvertedReadAttribute(ReadAttributePtr base_attribute, const CPPType &to_type)
+ : ReadAttribute(base_attribute->domain(), to_type, base_attribute->size()),
+ from_type_(base_attribute->cpp_type()),
+ to_type_(to_type),
+ base_attribute_(std::move(base_attribute)),
+ conversions_(nodes::get_implicit_type_conversions())
+ {
+ if (from_type_.size() > MaxValueSize || from_type_.alignment() > MaxValueAlignment) {
+ throw std::runtime_error(
+ "type is larger than expected, the buffer size has to be increased");
+ }
+ }
+
+ void get_internal(const int64_t index, void *r_value) const override
+ {
+ AlignedBuffer<MaxValueSize, MaxValueAlignment> buffer;
+ base_attribute_->get(index, buffer.ptr());
+ conversions_.convert(from_type_, to_type_, buffer.ptr(), r_value);
+ }
+};
+
+/** \} */
+
+const blender::fn::CPPType *custom_data_type_to_cpp_type(const CustomDataType type)
+{
+ switch (type) {
+ case CD_PROP_FLOAT:
+ return &CPPType::get<float>();
+ case CD_PROP_FLOAT2:
+ return &CPPType::get<float2>();
+ case CD_PROP_FLOAT3:
+ return &CPPType::get<float3>();
+ case CD_PROP_INT32:
+ return &CPPType::get<int>();
+ case CD_PROP_COLOR:
+ return &CPPType::get<Color4f>();
+ default:
+ return nullptr;
+ }
+ return nullptr;
+}
+
+CustomDataType cpp_type_to_custom_data_type(const blender::fn::CPPType &type)
+{
+ if (type.is<float>()) {
+ return CD_PROP_FLOAT;
+ }
+ if (type.is<float2>()) {
+ return CD_PROP_FLOAT2;
+ }
+ if (type.is<float3>()) {
+ return CD_PROP_FLOAT3;
+ }
+ if (type.is<int>()) {
+ return CD_PROP_INT32;
+ }
+ if (type.is<Color4f>()) {
+ return CD_PROP_COLOR;
+ }
+ return static_cast<CustomDataType>(-1);
+}
+
+} // namespace blender::bke
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities for Accessing Attributes
+ * \{ */
+
+static ReadAttributePtr read_attribute_from_custom_data(const CustomData &custom_data,
+ const int size,
+ const StringRef attribute_name,
+ const AttributeDomain domain)
+{
+ using namespace blender;
+ using namespace blender::bke;
+ for (const CustomDataLayer &layer : Span(custom_data.layers, custom_data.totlayer)) {
+ if (layer.name != nullptr && layer.name == attribute_name) {
+ switch (layer.type) {
+ case CD_PROP_FLOAT:
+ return std::make_unique<ArrayReadAttribute<float>>(
+ domain, Span(static_cast<float *>(layer.data), size));
+ case CD_PROP_FLOAT2:
+ return std::make_unique<ArrayReadAttribute<float2>>(
+ domain, Span(static_cast<float2 *>(layer.data), size));
+ case CD_PROP_FLOAT3:
+ return std::make_unique<ArrayReadAttribute<float3>>(
+ domain, Span(static_cast<float3 *>(layer.data), size));
+ case CD_PROP_INT32:
+ return std::make_unique<ArrayReadAttribute<int>>(
+ domain, Span(static_cast<int *>(layer.data), size));
+ case CD_PROP_COLOR:
+ return std::make_unique<ArrayReadAttribute<Color4f>>(
+ domain, Span(static_cast<Color4f *>(layer.data), size));
+ }
+ }
+ }
+ return {};
+}
+
+static WriteAttributePtr write_attribute_from_custom_data(
+ CustomData &custom_data,
+ const int size,
+ const StringRef attribute_name,
+ const AttributeDomain domain,
+ const std::function<void()> &update_customdata_pointers)
+{
+
+ using namespace blender;
+ using namespace blender::bke;
+ for (const CustomDataLayer &layer : Span(custom_data.layers, custom_data.totlayer)) {
+ if (layer.name != nullptr && layer.name == attribute_name) {
+ const void *data_before = layer.data;
+ /* The data layer might be shared with someone else. Since the caller wants to modify it, we
+ * copy it first. */
+ CustomData_duplicate_referenced_layer_named(&custom_data, layer.type, layer.name, size);
+ if (data_before != layer.data) {
+ update_customdata_pointers();
+ }
+ switch (layer.type) {
+ case CD_PROP_FLOAT:
+ return std::make_unique<ArrayWriteAttribute<float>>(
+ domain, MutableSpan(static_cast<float *>(layer.data), size));
+ case CD_PROP_FLOAT2:
+ return std::make_unique<ArrayWriteAttribute<float2>>(
+ domain, MutableSpan(static_cast<float2 *>(layer.data), size));
+ case CD_PROP_FLOAT3:
+ return std::make_unique<ArrayWriteAttribute<float3>>(
+ domain, MutableSpan(static_cast<float3 *>(layer.data), size));
+ case CD_PROP_INT32:
+ return std::make_unique<ArrayWriteAttribute<int>>(
+ domain, MutableSpan(static_cast<int *>(layer.data), size));
+ case CD_PROP_COLOR:
+ return std::make_unique<ArrayWriteAttribute<Color4f>>(
+ domain, MutableSpan(static_cast<Color4f *>(layer.data), size));
+ }
+ }
+ }
+ return {};
+}
+
+/* Returns true when the layer was found and is deleted. */
+static bool delete_named_custom_data_layer(CustomData &custom_data,
+ const StringRef attribute_name,
+ const int size)
+{
+ for (const int index : blender::IndexRange(custom_data.totlayer)) {
+ const CustomDataLayer &layer = custom_data.layers[index];
+ if (layer.name == attribute_name) {
+ CustomData_free_layer(&custom_data, layer.type, size, index);
+ return true;
+ }
+ }
+ return false;
+}
+
+static void get_custom_data_layer_attribute_names(const CustomData &custom_data,
+ const GeometryComponent &component,
+ const AttributeDomain domain,
+ Set<std::string> &r_names)
+{
+ for (const CustomDataLayer &layer : blender::Span(custom_data.layers, custom_data.totlayer)) {
+ if (component.attribute_domain_with_type_supported(domain,
+ static_cast<CustomDataType>(layer.type))) {
+ r_names.add(layer.name);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Geometry Component
+ * \{ */
+
+bool GeometryComponent::attribute_domain_supported(const AttributeDomain UNUSED(domain)) const
+{
+ return false;
+}
+
+bool GeometryComponent::attribute_domain_with_type_supported(
+ const AttributeDomain UNUSED(domain), const CustomDataType UNUSED(data_type)) const
+{
+ return false;
+}
+
+int GeometryComponent::attribute_domain_size(const AttributeDomain UNUSED(domain)) const
+{
+ BLI_assert(false);
+ return 0;
+}
+
+bool GeometryComponent::attribute_is_builtin(const StringRef UNUSED(attribute_name)) const
+{
+ return true;
+}
+
+ReadAttributePtr GeometryComponent::attribute_try_get_for_read(
+ const StringRef UNUSED(attribute_name)) const
+{
+ return {};
+}
+
+ReadAttributePtr GeometryComponent::attribute_try_adapt_domain(ReadAttributePtr attribute,
+ const AttributeDomain domain) const
+{
+ if (attribute && attribute->domain() == domain) {
+ return attribute;
+ }
+ return {};
+}
+
+WriteAttributePtr GeometryComponent::attribute_try_get_for_write(
+ const StringRef UNUSED(attribute_name))
+{
+ return {};
+}
+
+bool GeometryComponent::attribute_try_delete(const StringRef UNUSED(attribute_name))
+{
+ return false;
+}
+
+bool GeometryComponent::attribute_try_create(const StringRef UNUSED(attribute_name),
+ const AttributeDomain UNUSED(domain),
+ const CustomDataType UNUSED(data_type))
+{
+ return false;
+}
+
+Set<std::string> GeometryComponent::attribute_names() const
+{
+ return {};
+}
+
+static ReadAttributePtr try_adapt_data_type(ReadAttributePtr attribute,
+ const blender::fn::CPPType &to_type)
+{
+ const blender::fn::CPPType &from_type = attribute->cpp_type();
+ if (from_type == to_type) {
+ return attribute;
+ }
+
+ const blender::nodes::DataTypeConversions &conversions =
+ blender::nodes::get_implicit_type_conversions();
+ if (!conversions.is_convertible(from_type, to_type)) {
+ return {};
+ }
+
+ return std::make_unique<blender::bke::ConvertedReadAttribute>(std::move(attribute), to_type);
+}
+
+ReadAttributePtr GeometryComponent::attribute_try_get_for_read(
+ const StringRef attribute_name,
+ const AttributeDomain domain,
+ const CustomDataType data_type) const
+{
+ if (!this->attribute_domain_with_type_supported(domain, data_type)) {
+ return {};
+ }
+
+ ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name);
+ if (!attribute) {
+ return {};
+ }
+
+ if (attribute->domain() != domain) {
+ attribute = this->attribute_try_adapt_domain(std::move(attribute), domain);
+ if (!attribute) {
+ return {};
+ }
+ }
+
+ const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
+ BLI_assert(cpp_type != nullptr);
+ if (attribute->cpp_type() != *cpp_type) {
+ attribute = try_adapt_data_type(std::move(attribute), *cpp_type);
+ if (!attribute) {
+ return {};
+ }
+ }
+
+ return attribute;
+}
+
+ReadAttributePtr GeometryComponent::attribute_get_for_read(const StringRef attribute_name,
+ const AttributeDomain domain,
+ const CustomDataType data_type,
+ const void *default_value) const
+{
+ BLI_assert(this->attribute_domain_with_type_supported(domain, data_type));
+
+ ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name, domain, data_type);
+ if (attribute) {
+ return attribute;
+ }
+ return this->attribute_get_constant_for_read(domain, data_type, default_value);
+}
+
+blender::bke::ReadAttributePtr GeometryComponent::attribute_get_constant_for_read(
+ const AttributeDomain domain, const CustomDataType data_type, const void *value) const
+{
+ BLI_assert(this->attribute_domain_supported(domain));
+ const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
+ BLI_assert(cpp_type != nullptr);
+ if (value == nullptr) {
+ value = cpp_type->default_value();
+ }
+ const int domain_size = this->attribute_domain_size(domain);
+ return std::make_unique<blender::bke::ConstantReadAttribute>(
+ domain, domain_size, *cpp_type, value);
+}
+
+WriteAttributePtr GeometryComponent::attribute_try_ensure_for_write(const StringRef attribute_name,
+ const AttributeDomain domain,
+ const CustomDataType data_type)
+{
+ const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
+ BLI_assert(cpp_type != nullptr);
+
+ WriteAttributePtr attribute = this->attribute_try_get_for_write(attribute_name);
+ if (attribute && attribute->domain() == domain && attribute->cpp_type() == *cpp_type) {
+ return attribute;
+ }
+
+ if (attribute) {
+ if (!this->attribute_try_delete(attribute_name)) {
+ return {};
+ }
+ }
+ if (!this->attribute_domain_with_type_supported(domain, data_type)) {
+ return {};
+ }
+ if (!this->attribute_try_create(attribute_name, domain, data_type)) {
+ return {};
+ }
+ return this->attribute_try_get_for_write(attribute_name);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Point Cloud Component
+ * \{ */
+
+bool PointCloudComponent::attribute_domain_supported(const AttributeDomain domain) const
+{
+ return domain == ATTR_DOMAIN_POINT;
+}
+
+bool PointCloudComponent::attribute_domain_with_type_supported(
+ const AttributeDomain domain, const CustomDataType data_type) const
+{
+ return domain == ATTR_DOMAIN_POINT && ELEM(data_type,
+ CD_PROP_FLOAT,
+ CD_PROP_FLOAT2,
+ CD_PROP_FLOAT3,
+ CD_PROP_INT32,
+ CD_PROP_COLOR);
+}
+
+int PointCloudComponent::attribute_domain_size(const AttributeDomain domain) const
+{
+ BLI_assert(domain == ATTR_DOMAIN_POINT);
+ UNUSED_VARS_NDEBUG(domain);
+ if (pointcloud_ == nullptr) {
+ return 0;
+ }
+ return pointcloud_->totpoint;
+}
+
+bool PointCloudComponent::attribute_is_builtin(const StringRef attribute_name) const
+{
+ return attribute_name == "position";
+}
+
+ReadAttributePtr PointCloudComponent::attribute_try_get_for_read(
+ const StringRef attribute_name) const
+{
+ if (pointcloud_ == nullptr) {
+ return {};
+ }
+
+ return read_attribute_from_custom_data(
+ pointcloud_->pdata, pointcloud_->totpoint, attribute_name, ATTR_DOMAIN_POINT);
+}
+
+WriteAttributePtr PointCloudComponent::attribute_try_get_for_write(const StringRef attribute_name)
+{
+ PointCloud *pointcloud = this->get_for_write();
+ if (pointcloud == nullptr) {
+ return {};
+ }
+
+ return write_attribute_from_custom_data(
+ pointcloud->pdata, pointcloud->totpoint, attribute_name, ATTR_DOMAIN_POINT, [&]() {
+ BKE_pointcloud_update_customdata_pointers(pointcloud);
+ });
+}
+
+bool PointCloudComponent::attribute_try_delete(const StringRef attribute_name)
+{
+ if (this->attribute_is_builtin(attribute_name)) {
+ return false;
+ }
+ PointCloud *pointcloud = this->get_for_write();
+ if (pointcloud == nullptr) {
+ return false;
+ }
+ delete_named_custom_data_layer(pointcloud->pdata, attribute_name, pointcloud->totpoint);
+ return true;
+}
+
+static bool custom_data_has_layer_with_name(const CustomData &custom_data, const StringRef name)
+{
+ for (const CustomDataLayer &layer : blender::Span(custom_data.layers, custom_data.totlayer)) {
+ if (layer.name == name) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool PointCloudComponent::attribute_try_create(const StringRef attribute_name,
+ const AttributeDomain domain,
+ const CustomDataType data_type)
+{
+ if (this->attribute_is_builtin(attribute_name)) {
+ return false;
+ }
+ if (!this->attribute_domain_with_type_supported(domain, data_type)) {
+ return false;
+ }
+ PointCloud *pointcloud = this->get_for_write();
+ if (pointcloud == nullptr) {
+ return false;
+ }
+ if (custom_data_has_layer_with_name(pointcloud->pdata, attribute_name)) {
+ return false;
+ }
+
+ char attribute_name_c[MAX_NAME];
+ attribute_name.copy(attribute_name_c);
+ CustomData_add_layer_named(
+ &pointcloud->pdata, data_type, CD_DEFAULT, nullptr, pointcloud_->totpoint, attribute_name_c);
+ return true;
+}
+
+Set<std::string> PointCloudComponent::attribute_names() const
+{
+ if (pointcloud_ == nullptr) {
+ return {};
+ }
+
+ Set<std::string> names;
+ get_custom_data_layer_attribute_names(pointcloud_->pdata, *this, ATTR_DOMAIN_POINT, names);
+ return names;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh Component
+ * \{ */
+
+bool MeshComponent::attribute_domain_supported(const AttributeDomain domain) const
+{
+ return ELEM(
+ domain, ATTR_DOMAIN_CORNER, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_POLYGON);
+}
+
+bool MeshComponent::attribute_domain_with_type_supported(const AttributeDomain domain,
+ const CustomDataType data_type) const
+{
+ if (!this->attribute_domain_supported(domain)) {
+ return false;
+ }
+ return ELEM(
+ data_type, CD_PROP_FLOAT, CD_PROP_FLOAT2, CD_PROP_FLOAT3, CD_PROP_INT32, CD_PROP_COLOR);
+}
+
+int MeshComponent::attribute_domain_size(const AttributeDomain domain) const
+{
+ BLI_assert(this->attribute_domain_supported(domain));
+ if (mesh_ == nullptr) {
+ return 0;
+ }
+ switch (domain) {
+ case ATTR_DOMAIN_CORNER:
+ return mesh_->totloop;
+ case ATTR_DOMAIN_POINT:
+ return mesh_->totvert;
+ case ATTR_DOMAIN_EDGE:
+ return mesh_->totedge;
+ case ATTR_DOMAIN_POLYGON:
+ return mesh_->totpoly;
+ default:
+ BLI_assert(false);
+ break;
+ }
+ return 0;
+}
+
+bool MeshComponent::attribute_is_builtin(const StringRef attribute_name) const
+{
+ return attribute_name == "position";
+}
+
+ReadAttributePtr MeshComponent::attribute_try_get_for_read(const StringRef attribute_name) const
+{
+ if (mesh_ == nullptr) {
+ return {};
+ }
+
+ if (attribute_name == "position") {
+ auto get_vertex_position = [](const MVert &vert) { return float3(vert.co); };
+ return std::make_unique<
+ blender::bke::DerivedArrayReadAttribute<MVert, float3, decltype(get_vertex_position)>>(
+ ATTR_DOMAIN_POINT, blender::Span(mesh_->mvert, mesh_->totvert), get_vertex_position);
+ }
+
+ ReadAttributePtr corner_attribute = read_attribute_from_custom_data(
+ mesh_->ldata, mesh_->totloop, attribute_name, ATTR_DOMAIN_CORNER);
+ if (corner_attribute) {
+ return corner_attribute;
+ }
+
+ const int vertex_group_index = vertex_group_names_.lookup_default(attribute_name, -1);
+ if (vertex_group_index >= 0) {
+ return std::make_unique<blender::bke::VertexWeightReadAttribute>(
+ mesh_->dvert, mesh_->totvert, vertex_group_index);
+ }
+
+ ReadAttributePtr vertex_attribute = read_attribute_from_custom_data(
+ mesh_->vdata, mesh_->totvert, attribute_name, ATTR_DOMAIN_POINT);
+ if (vertex_attribute) {
+ return vertex_attribute;
+ }
+
+ ReadAttributePtr edge_attribute = read_attribute_from_custom_data(
+ mesh_->edata, mesh_->totedge, attribute_name, ATTR_DOMAIN_EDGE);
+ if (edge_attribute) {
+ return edge_attribute;
+ }
+
+ ReadAttributePtr polygon_attribute = read_attribute_from_custom_data(
+ mesh_->pdata, mesh_->totpoly, attribute_name, ATTR_DOMAIN_POLYGON);
+ if (polygon_attribute) {
+ return polygon_attribute;
+ }
+
+ return {};
+}
+
+WriteAttributePtr MeshComponent::attribute_try_get_for_write(const StringRef attribute_name)
+{
+ Mesh *mesh = this->get_for_write();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ const std::function<void()> update_mesh_pointers = [&]() {
+ BKE_mesh_update_customdata_pointers(mesh, false);
+ };
+
+ if (attribute_name == "position") {
+ CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert);
+ update_mesh_pointers();
+
+ auto get_vertex_position = [](const MVert &vert) { return float3(vert.co); };
+ auto set_vertex_position = [](MVert &vert, const float3 &co) { copy_v3_v3(vert.co, co); };
+ return std::make_unique<
+ blender::bke::DerivedArrayWriteAttribute<MVert,
+ float3,
+ decltype(get_vertex_position),
+ decltype(set_vertex_position)>>(
+ ATTR_DOMAIN_POINT,
+ blender::MutableSpan(mesh_->mvert, mesh_->totvert),
+ get_vertex_position,
+ set_vertex_position);
+ }
+
+ WriteAttributePtr corner_attribute = write_attribute_from_custom_data(
+ mesh_->ldata, mesh_->totloop, attribute_name, ATTR_DOMAIN_CORNER, update_mesh_pointers);
+ if (corner_attribute) {
+ return corner_attribute;
+ }
+
+ const int vertex_group_index = vertex_group_names_.lookup_default_as(attribute_name, -1);
+ if (vertex_group_index >= 0) {
+ if (mesh_->dvert == nullptr) {
+ BKE_object_defgroup_data_create(&mesh_->id);
+ }
+ return std::make_unique<blender::bke::VertexWeightWriteAttribute>(
+ mesh_->dvert, mesh_->totvert, vertex_group_index);
+ }
+
+ WriteAttributePtr vertex_attribute = write_attribute_from_custom_data(
+ mesh_->vdata, mesh_->totvert, attribute_name, ATTR_DOMAIN_POINT, update_mesh_pointers);
+ if (vertex_attribute) {
+ return vertex_attribute;
+ }
+
+ WriteAttributePtr edge_attribute = write_attribute_from_custom_data(
+ mesh_->edata, mesh_->totedge, attribute_name, ATTR_DOMAIN_EDGE, update_mesh_pointers);
+ if (edge_attribute) {
+ return edge_attribute;
+ }
+
+ WriteAttributePtr polygon_attribute = write_attribute_from_custom_data(
+ mesh_->pdata, mesh_->totpoly, attribute_name, ATTR_DOMAIN_POLYGON, update_mesh_pointers);
+ if (polygon_attribute) {
+ return polygon_attribute;
+ }
+
+ return {};
+}
+
+bool MeshComponent::attribute_try_delete(const StringRef attribute_name)
+{
+ if (this->attribute_is_builtin(attribute_name)) {
+ return false;
+ }
+ Mesh *mesh = this->get_for_write();
+ if (mesh == nullptr) {
+ return false;
+ }
+
+ delete_named_custom_data_layer(mesh_->ldata, attribute_name, mesh_->totloop);
+ delete_named_custom_data_layer(mesh_->vdata, attribute_name, mesh_->totvert);
+ delete_named_custom_data_layer(mesh_->edata, attribute_name, mesh_->totedge);
+ delete_named_custom_data_layer(mesh_->pdata, attribute_name, mesh_->totpoly);
+
+ const int vertex_group_index = vertex_group_names_.lookup_default_as(attribute_name, -1);
+ if (vertex_group_index != -1) {
+ for (MDeformVert &dvert : blender::MutableSpan(mesh_->dvert, mesh_->totvert)) {
+ MDeformWeight *weight = BKE_defvert_find_index(&dvert, vertex_group_index);
+ BKE_defvert_remove_group(&dvert, weight);
+ }
+ vertex_group_names_.remove_as(attribute_name);
+ }
+
+ return true;
+}
+
+bool MeshComponent::attribute_try_create(const StringRef attribute_name,
+ const AttributeDomain domain,
+ const CustomDataType data_type)
+{
+ if (this->attribute_is_builtin(attribute_name)) {
+ return false;
+ }
+ if (!this->attribute_domain_with_type_supported(domain, data_type)) {
+ return false;
+ }
+ Mesh *mesh = this->get_for_write();
+ if (mesh == nullptr) {
+ return false;
+ }
+
+ char attribute_name_c[MAX_NAME];
+ attribute_name.copy(attribute_name_c);
+
+ switch (domain) {
+ case ATTR_DOMAIN_CORNER: {
+ if (custom_data_has_layer_with_name(mesh->ldata, attribute_name)) {
+ return false;
+ }
+ CustomData_add_layer_named(
+ &mesh->ldata, data_type, CD_DEFAULT, nullptr, mesh->totloop, attribute_name_c);
+ return true;
+ }
+ case ATTR_DOMAIN_POINT: {
+ if (custom_data_has_layer_with_name(mesh->vdata, attribute_name)) {
+ return false;
+ }
+ if (vertex_group_names_.contains_as(attribute_name)) {
+ return false;
+ }
+ CustomData_add_layer_named(
+ &mesh->vdata, data_type, CD_DEFAULT, nullptr, mesh->totvert, attribute_name_c);
+ return true;
+ }
+ case ATTR_DOMAIN_EDGE: {
+ if (custom_data_has_layer_with_name(mesh->edata, attribute_name)) {
+ return false;
+ }
+ CustomData_add_layer_named(
+ &mesh->edata, data_type, CD_DEFAULT, nullptr, mesh->totedge, attribute_name_c);
+ return true;
+ }
+ case ATTR_DOMAIN_POLYGON: {
+ if (custom_data_has_layer_with_name(mesh->pdata, attribute_name)) {
+ return false;
+ }
+ CustomData_add_layer_named(
+ &mesh->pdata, data_type, CD_DEFAULT, nullptr, mesh->totpoly, attribute_name_c);
+ return true;
+ }
+ default:
+ return false;
+ }
+}
+
+Set<std::string> MeshComponent::attribute_names() const
+{
+ if (mesh_ == nullptr) {
+ return {};
+ }
+
+ Set<std::string> names;
+ names.add("position");
+ for (StringRef name : vertex_group_names_.keys()) {
+ names.add(name);
+ }
+ get_custom_data_layer_attribute_names(mesh_->pdata, *this, ATTR_DOMAIN_CORNER, names);
+ get_custom_data_layer_attribute_names(mesh_->vdata, *this, ATTR_DOMAIN_POINT, names);
+ get_custom_data_layer_attribute_names(mesh_->edata, *this, ATTR_DOMAIN_EDGE, names);
+ get_custom_data_layer_attribute_names(mesh_->pdata, *this, ATTR_DOMAIN_POLYGON, names);
+ return names;
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index 434456a922e..73ca490c395 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -4559,7 +4559,7 @@ void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_typ
if (psys->part->type == particle_type) {
/* clear modifier */
pfmd = psys_get_modifier(ob, psys);
- BLI_remlink(&ob->modifiers, pfmd);
+ BLI_remlink(&ob->modifiers, (ModifierData *)pfmd);
BKE_modifier_free((ModifierData *)pfmd);
/* clear particle system */
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
new file mode 100644
index 00000000000..28695d769d3
--- /dev/null
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -0,0 +1,554 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BKE_geometry_set.hh"
+#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_wrapper.h"
+#include "BKE_pointcloud.h"
+
+#include "DNA_object_types.h"
+
+#include "MEM_guardedalloc.h"
+
+using blender::float3;
+using blender::MutableSpan;
+using blender::Span;
+using blender::StringRef;
+using blender::Vector;
+
+/* -------------------------------------------------------------------- */
+/** \name Geometry Component
+ * \{ */
+
+GeometryComponent::GeometryComponent(GeometryComponentType type) : type_(type)
+{
+}
+
+GeometryComponent ::~GeometryComponent()
+{
+}
+
+GeometryComponent *GeometryComponent::create(GeometryComponentType component_type)
+{
+ switch (component_type) {
+ case GeometryComponentType::Mesh:
+ return new MeshComponent();
+ case GeometryComponentType::PointCloud:
+ return new PointCloudComponent();
+ case GeometryComponentType::Instances:
+ return new InstancesComponent();
+ }
+ BLI_assert(false);
+ return nullptr;
+}
+
+void GeometryComponent::user_add() const
+{
+ users_.fetch_add(1);
+}
+
+void GeometryComponent::user_remove() const
+{
+ const int new_users = users_.fetch_sub(1) - 1;
+ if (new_users == 0) {
+ delete this;
+ }
+}
+
+bool GeometryComponent::is_mutable() const
+{
+ /* If the item is shared, it is read-only. */
+ /* The user count can be 0, when this is called from the destructor. */
+ return users_ <= 1;
+}
+
+GeometryComponentType GeometryComponent::type() const
+{
+ return type_;
+}
+
+bool GeometryComponent::is_empty() const
+{
+ return false;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Geometry Set
+ * \{ */
+
+/* This method can only be used when the geometry set is mutable. It returns a mutable geometry
+ * component of the given type.
+ */
+GeometryComponent &GeometrySet::get_component_for_write(GeometryComponentType component_type)
+{
+ return components_.add_or_modify(
+ component_type,
+ [&](GeometryComponentPtr *value_ptr) -> GeometryComponent & {
+ /* If the component did not exist before, create a new one. */
+ new (value_ptr) GeometryComponentPtr(GeometryComponent::create(component_type));
+ return **value_ptr;
+ },
+ [&](GeometryComponentPtr *value_ptr) -> GeometryComponent & {
+ GeometryComponentPtr &value = *value_ptr;
+ if (value->is_mutable()) {
+ /* If the referenced component is already mutable, return it directly. */
+ return *value;
+ }
+ /* If the referenced component is shared, make a copy. The copy is not shared and is
+ * therefore mutable. */
+ GeometryComponent *copied_component = value->copy();
+ value = GeometryComponentPtr{copied_component};
+ return *copied_component;
+ });
+}
+
+/* Get the component of the given type. Might return null if the component does not exist yet. */
+const GeometryComponent *GeometrySet::get_component_for_read(
+ GeometryComponentType component_type) const
+{
+ const GeometryComponentPtr *component = components_.lookup_ptr(component_type);
+ if (component != nullptr) {
+ return component->get();
+ }
+ return nullptr;
+}
+
+bool GeometrySet::has(const GeometryComponentType component_type) const
+{
+ return components_.contains(component_type);
+}
+
+void GeometrySet::remove(const GeometryComponentType component_type)
+{
+ components_.remove(component_type);
+}
+
+void GeometrySet::add(const GeometryComponent &component)
+{
+ BLI_assert(!components_.contains(component.type()));
+ component.user_add();
+ GeometryComponentPtr component_ptr{const_cast<GeometryComponent *>(&component)};
+ components_.add_new(component.type(), std::move(component_ptr));
+}
+
+void GeometrySet::compute_boundbox_without_instances(float3 *r_min, float3 *r_max) const
+{
+ const PointCloud *pointcloud = this->get_pointcloud_for_read();
+ if (pointcloud != nullptr) {
+ BKE_pointcloud_minmax(pointcloud, *r_min, *r_max);
+ }
+ const Mesh *mesh = this->get_mesh_for_read();
+ if (mesh != nullptr) {
+ BKE_mesh_wrapper_minmax(mesh, *r_min, *r_max);
+ }
+}
+
+std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set)
+{
+ stream << "<GeometrySet at " << &geometry_set << ", " << geometry_set.components_.size()
+ << " components>";
+ return stream;
+}
+
+/* This generally should not be used. It is necessary currently, so that GeometrySet can by used by
+ * the CPPType system. */
+bool operator==(const GeometrySet &UNUSED(a), const GeometrySet &UNUSED(b))
+{
+ return false;
+}
+
+/* This generally should not be used. It is necessary currently, so that GeometrySet can by used by
+ * the CPPType system. */
+uint64_t GeometrySet::hash() const
+{
+ return reinterpret_cast<uint64_t>(this);
+}
+
+/* Returns a read-only mesh or null. */
+const Mesh *GeometrySet::get_mesh_for_read() const
+{
+ const MeshComponent *component = this->get_component_for_read<MeshComponent>();
+ return (component == nullptr) ? nullptr : component->get_for_read();
+}
+
+/* Returns true when the geometry set has a mesh component that has a mesh. */
+bool GeometrySet::has_mesh() const
+{
+ const MeshComponent *component = this->get_component_for_read<MeshComponent>();
+ return component != nullptr && component->has_mesh();
+}
+
+/* Returns a read-only point cloud of null. */
+const PointCloud *GeometrySet::get_pointcloud_for_read() const
+{
+ const PointCloudComponent *component = this->get_component_for_read<PointCloudComponent>();
+ return (component == nullptr) ? nullptr : component->get_for_read();
+}
+
+/* Returns true when the geometry set has a point cloud component that has a point cloud. */
+bool GeometrySet::has_pointcloud() const
+{
+ const PointCloudComponent *component = this->get_component_for_read<PointCloudComponent>();
+ return component != nullptr && component->has_pointcloud();
+}
+
+/* Returns true when the geometry set has an instances component that has at least one instance. */
+bool GeometrySet::has_instances() const
+{
+ const InstancesComponent *component = this->get_component_for_read<InstancesComponent>();
+ return component != nullptr && component->instances_amount() >= 1;
+}
+
+/* Create a new geometry set that only contains the given mesh. */
+GeometrySet GeometrySet::create_with_mesh(Mesh *mesh, GeometryOwnershipType ownership)
+{
+ GeometrySet geometry_set;
+ MeshComponent &component = geometry_set.get_component_for_write<MeshComponent>();
+ component.replace(mesh, ownership);
+ return geometry_set;
+}
+
+/* Create a new geometry set that only contains the given point cloud. */
+GeometrySet GeometrySet::create_with_pointcloud(PointCloud *pointcloud,
+ GeometryOwnershipType ownership)
+{
+ GeometrySet geometry_set;
+ PointCloudComponent &component = geometry_set.get_component_for_write<PointCloudComponent>();
+ component.replace(pointcloud, ownership);
+ return geometry_set;
+}
+
+/* Clear the existing mesh and replace it with the given one. */
+void GeometrySet::replace_mesh(Mesh *mesh, GeometryOwnershipType ownership)
+{
+ MeshComponent &component = this->get_component_for_write<MeshComponent>();
+ component.replace(mesh, ownership);
+}
+
+/* Clear the existing point cloud and replace with the given one. */
+void GeometrySet::replace_pointcloud(PointCloud *pointcloud, GeometryOwnershipType ownership)
+{
+ PointCloudComponent &pointcloud_component = this->get_component_for_write<PointCloudComponent>();
+ pointcloud_component.replace(pointcloud, ownership);
+}
+
+/* Returns a mutable mesh or null. No ownership is transferred. */
+Mesh *GeometrySet::get_mesh_for_write()
+{
+ MeshComponent &component = this->get_component_for_write<MeshComponent>();
+ return component.get_for_write();
+}
+
+/* Returns a mutable point cloud or null. No ownership is transferred. */
+PointCloud *GeometrySet::get_pointcloud_for_write()
+{
+ PointCloudComponent &component = this->get_component_for_write<PointCloudComponent>();
+ return component.get_for_write();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh Component
+ * \{ */
+
+MeshComponent::MeshComponent() : GeometryComponent(GeometryComponentType::Mesh)
+{
+}
+
+MeshComponent::~MeshComponent()
+{
+ this->clear();
+}
+
+GeometryComponent *MeshComponent::copy() const
+{
+ MeshComponent *new_component = new MeshComponent();
+ if (mesh_ != nullptr) {
+ new_component->mesh_ = BKE_mesh_copy_for_eval(mesh_, false);
+ new_component->ownership_ = GeometryOwnershipType::Owned;
+ }
+ return new_component;
+}
+
+void MeshComponent::clear()
+{
+ BLI_assert(this->is_mutable());
+ if (mesh_ != nullptr) {
+ if (ownership_ == GeometryOwnershipType::Owned) {
+ BKE_id_free(nullptr, mesh_);
+ }
+ mesh_ = nullptr;
+ }
+ vertex_group_names_.clear();
+}
+
+bool MeshComponent::has_mesh() const
+{
+ return mesh_ != nullptr;
+}
+
+/* Clear the component and replace it with the new mesh. */
+void MeshComponent::replace(Mesh *mesh, GeometryOwnershipType ownership)
+{
+ BLI_assert(this->is_mutable());
+ this->clear();
+ mesh_ = mesh;
+ ownership_ = ownership;
+}
+
+/* Return the mesh and clear the component. The caller takes over responsibility for freeing the
+ * mesh (if the component was responsible before). */
+Mesh *MeshComponent::release()
+{
+ BLI_assert(this->is_mutable());
+ Mesh *mesh = mesh_;
+ mesh_ = nullptr;
+ return mesh;
+}
+
+void MeshComponent::copy_vertex_group_names_from_object(const Object &object)
+{
+ BLI_assert(this->is_mutable());
+ vertex_group_names_.clear();
+ int index = 0;
+ LISTBASE_FOREACH (const bDeformGroup *, group, &object.defbase) {
+ vertex_group_names_.add(group->name, index);
+ index++;
+ }
+}
+
+/* Get the mesh from this component. This method can be used by multiple threads at the same
+ * time. Therefore, the returned mesh should not be modified. No ownership is transferred. */
+const Mesh *MeshComponent::get_for_read() const
+{
+ return mesh_;
+}
+
+/* Get the mesh from this component. This method can only be used when the component is mutable,
+ * i.e. it is not shared. The returned mesh can be modified. No ownership is transferred. */
+Mesh *MeshComponent::get_for_write()
+{
+ BLI_assert(this->is_mutable());
+ if (ownership_ == GeometryOwnershipType::ReadOnly) {
+ mesh_ = BKE_mesh_copy_for_eval(mesh_, false);
+ ownership_ = GeometryOwnershipType::Owned;
+ }
+ return mesh_;
+}
+
+bool MeshComponent::is_empty() const
+{
+ return mesh_ == nullptr;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pointcloud Component
+ * \{ */
+
+PointCloudComponent::PointCloudComponent() : GeometryComponent(GeometryComponentType::PointCloud)
+{
+}
+
+PointCloudComponent::~PointCloudComponent()
+{
+ this->clear();
+}
+
+GeometryComponent *PointCloudComponent::copy() const
+{
+ PointCloudComponent *new_component = new PointCloudComponent();
+ if (pointcloud_ != nullptr) {
+ new_component->pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false);
+ new_component->ownership_ = GeometryOwnershipType::Owned;
+ }
+ return new_component;
+}
+
+void PointCloudComponent::clear()
+{
+ BLI_assert(this->is_mutable());
+ if (pointcloud_ != nullptr) {
+ if (ownership_ == GeometryOwnershipType::Owned) {
+ BKE_id_free(nullptr, pointcloud_);
+ }
+ pointcloud_ = nullptr;
+ }
+}
+
+bool PointCloudComponent::has_pointcloud() const
+{
+ return pointcloud_ != nullptr;
+}
+
+/* Clear the component and replace it with the new point cloud. */
+void PointCloudComponent::replace(PointCloud *pointcloud, GeometryOwnershipType ownership)
+{
+ BLI_assert(this->is_mutable());
+ this->clear();
+ pointcloud_ = pointcloud;
+ ownership_ = ownership;
+}
+
+/* Return the point cloud and clear the component. The caller takes over responsibility for freeing
+ * the point cloud (if the component was responsible before). */
+PointCloud *PointCloudComponent::release()
+{
+ BLI_assert(this->is_mutable());
+ PointCloud *pointcloud = pointcloud_;
+ pointcloud_ = nullptr;
+ return pointcloud;
+}
+
+/* Get the point cloud from this component. This method can be used by multiple threads at the same
+ * time. Therefore, the returned point cloud should not be modified. No ownership is transferred.
+ */
+const PointCloud *PointCloudComponent::get_for_read() const
+{
+ return pointcloud_;
+}
+
+/* Get the point cloud from this component. This method can only be used when the component is
+ * mutable, i.e. it is not shared. The returned point cloud can be modified. No ownership is
+ * transferred. */
+PointCloud *PointCloudComponent::get_for_write()
+{
+ BLI_assert(this->is_mutable());
+ if (ownership_ == GeometryOwnershipType::ReadOnly) {
+ pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false);
+ ownership_ = GeometryOwnershipType::Owned;
+ }
+ return pointcloud_;
+}
+
+bool PointCloudComponent::is_empty() const
+{
+ return pointcloud_ == nullptr;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Instances Component
+ * \{ */
+
+InstancesComponent::InstancesComponent() : GeometryComponent(GeometryComponentType::Instances)
+{
+}
+
+GeometryComponent *InstancesComponent::copy() const
+{
+ InstancesComponent *new_component = new InstancesComponent();
+ new_component->positions_ = positions_;
+ new_component->rotations_ = rotations_;
+ new_component->scales_ = scales_;
+ new_component->objects_ = objects_;
+ return new_component;
+}
+
+void InstancesComponent::clear()
+{
+ objects_.clear();
+ positions_.clear();
+ rotations_.clear();
+ scales_.clear();
+}
+void InstancesComponent::add_instance(const Object *object,
+ blender::float3 position,
+ blender::float3 rotation,
+ blender::float3 scale)
+{
+ objects_.append(object);
+ positions_.append(position);
+ rotations_.append(rotation);
+ scales_.append(scale);
+}
+
+Span<const Object *> InstancesComponent::objects() const
+{
+ return objects_;
+}
+
+Span<float3> InstancesComponent::positions() const
+{
+ return positions_;
+}
+
+blender::Span<blender::float3> InstancesComponent::rotations() const
+{
+ return rotations_;
+}
+
+blender::Span<blender::float3> InstancesComponent::scales() const
+{
+ return scales_;
+}
+
+MutableSpan<float3> InstancesComponent::positions()
+{
+ return positions_;
+}
+
+int InstancesComponent::instances_amount() const
+{
+ BLI_assert(positions_.size() == objects_.size());
+ return objects_.size();
+}
+
+bool InstancesComponent::is_empty() const
+{
+ return positions_.size() == 0;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name C API
+ * \{ */
+
+void BKE_geometry_set_free(GeometrySet *geometry_set)
+{
+ delete geometry_set;
+}
+
+bool BKE_geometry_set_has_instances(const GeometrySet *geometry_set)
+{
+ return geometry_set->get_component_for_read<InstancesComponent>() != nullptr;
+}
+
+int BKE_geometry_set_instances(const GeometrySet *geometry_set,
+ float (**r_positions)[3],
+ float (**r_rotations)[3],
+ float (**r_scales)[3],
+ Object ***r_objects)
+{
+ const InstancesComponent *component = geometry_set->get_component_for_read<InstancesComponent>();
+ if (component == nullptr) {
+ return 0;
+ }
+ *r_positions = (float(*)[3])component->positions().data();
+ *r_rotations = (float(*)[3])component->rotations().data();
+ *r_scales = (float(*)[3])component->scales().data();
+ *r_objects = (Object **)component->objects().data();
+ return component->instances_amount();
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/hair.c b/source/blender/blenkernel/intern/hair.c
index 554919ad1a0..a44b054e366 100644
--- a/source/blender/blenkernel/intern/hair.c
+++ b/source/blender/blenkernel/intern/hair.c
@@ -49,8 +49,8 @@
#include "BLO_read_write.h"
-static const char *HAIR_ATTR_POSITION = "Position";
-static const char *HAIR_ATTR_RADIUS = "Radius";
+static const char *HAIR_ATTR_POSITION = "position";
+static const char *HAIR_ATTR_RADIUS = "radius";
/* Hair datablock */
diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c
index f0031d4191d..9e3189afee9 100644
--- a/source/blender/blenkernel/intern/lib_remap.c
+++ b/source/blender/blenkernel/intern/lib_remap.c
@@ -342,7 +342,7 @@ static void libblock_remap_data_postprocess_obdata_relink(Main *bmain, Object *o
static void libblock_remap_data_postprocess_nodetree_update(Main *bmain, ID *new_id)
{
/* Update all group nodes using a node group. */
- ntreeUpdateAllUsers(bmain, new_id);
+ ntreeUpdateAllUsers(bmain, (bNodeTree *)new_id);
}
/**
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index e639bb319a3..b564a4c468b 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -39,6 +39,7 @@
#include "DNA_light_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_material_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_node_types.h"
#include "DNA_scene_types.h"
#include "DNA_simulation_types.h"
@@ -65,7 +66,6 @@
#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_node.h"
-#include "BKE_simulation.h"
#include "BLI_ghash.h"
#include "BLI_threads.h"
@@ -75,8 +75,8 @@
#include "NOD_common.h"
#include "NOD_composite.h"
#include "NOD_function.h"
+#include "NOD_geometry.h"
#include "NOD_shader.h"
-#include "NOD_simulation.h"
#include "NOD_socket.h"
#include "NOD_texture.h"
@@ -85,6 +85,8 @@
#include "BLO_read_write.h"
+#include "MOD_nodes.h"
+
#define NODE_DEFAULT_MAX_WIDTH 700
/* Fallback types for undefined tree, nodes, sockets */
@@ -3958,14 +3960,18 @@ void ntreeUpdateAllNew(Main *main)
FOREACH_NODETREE_END;
}
-void ntreeUpdateAllUsers(Main *main, ID *ngroup)
+void ntreeUpdateAllUsers(Main *main, bNodeTree *ngroup)
{
+ if (ngroup == NULL) {
+ return;
+ }
+
/* Update all users of ngroup, to add/remove sockets as needed. */
FOREACH_NODETREE_BEGIN (main, ntree, owner_id) {
bool need_update = false;
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->id == ngroup) {
+ if (node->id == &ngroup->id) {
if (node->typeinfo->group_update_func) {
node->typeinfo->group_update_func(ntree, node);
}
@@ -3979,6 +3985,19 @@ void ntreeUpdateAllUsers(Main *main, ID *ngroup)
}
}
FOREACH_NODETREE_END;
+
+ if (ngroup->type == NTREE_GEOMETRY) {
+ LISTBASE_FOREACH (Object *, object, &main->objects) {
+ LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
+ if (md->type == eModifierType_Nodes) {
+ NodesModifierData *nmd = (NodesModifierData *)md;
+ if (nmd->node_group == ngroup) {
+ MOD_nodes_update_interface(object, nmd);
+ }
+ }
+ }
+ }
+ }
}
void ntreeUpdateTree(Main *bmain, bNodeTree *ntree)
@@ -4022,7 +4041,7 @@ void ntreeUpdateTree(Main *bmain, bNodeTree *ntree)
}
if (bmain) {
- ntreeUpdateAllUsers(bmain, &ntree->id);
+ ntreeUpdateAllUsers(bmain, ntree);
}
if (ntree->update & (NTREE_UPDATE_LINKS | NTREE_UPDATE_NODES)) {
@@ -4659,9 +4678,21 @@ static void registerTextureNodes(void)
register_node_type_tex_proc_distnoise();
}
-static void registerSimulationNodes(void)
+static void registerGeometryNodes(void)
{
- register_node_type_sim_group();
+ register_node_type_geo_group();
+
+ register_node_type_geo_triangulate();
+ register_node_type_geo_edge_split();
+ register_node_type_geo_transform();
+ register_node_type_geo_subdivision_surface();
+ register_node_type_geo_boolean();
+ register_node_type_geo_point_distribute();
+ register_node_type_geo_point_instance();
+ register_node_type_geo_object_info();
+ register_node_type_geo_random_attribute();
+ register_node_type_geo_attribute_math();
+ register_node_type_geo_join_geometry();
}
static void registerFunctionNodes(void)
@@ -4688,7 +4719,7 @@ void BKE_node_system_init(void)
register_node_tree_type_cmp();
register_node_tree_type_sh();
register_node_tree_type_tex();
- register_node_tree_type_sim();
+ register_node_tree_type_geo();
register_node_type_frame();
register_node_type_reroute();
@@ -4698,7 +4729,7 @@ void BKE_node_system_init(void)
registerCompositNodes();
registerShaderNodes();
registerTextureNodes();
- registerSimulationNodes();
+ registerGeometryNodes();
registerFunctionNodes();
}
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 242c0edd5a4..31d2e3738f4 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -94,6 +94,7 @@
#include "BKE_fcurve.h"
#include "BKE_fcurve_driver.h"
#include "BKE_font.h"
+#include "BKE_geometry_set.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_geom.h"
@@ -1284,8 +1285,7 @@ bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type)
return (mti->modifyHair != NULL) || (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly);
}
if (ob->type == OB_POINTCLOUD) {
- return (mti->modifyPointCloud != NULL) ||
- (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly);
+ return (mti->modifyPointCloud != NULL);
}
if (ob->type == OB_VOLUME) {
return (mti->modifyVolume != NULL);
@@ -1507,6 +1507,9 @@ void BKE_object_eval_assign_data(Object *object_eval, ID *data_eval, bool is_own
object_eval->data = data_eval;
}
}
+
+ /* Is set separately currently. */
+ object_eval->runtime.geometry_set_eval = NULL;
}
/**
@@ -1551,6 +1554,11 @@ void BKE_object_free_derived_caches(Object *ob)
BKE_gpencil_eval_delete(ob->runtime.gpd_eval);
ob->runtime.gpd_eval = NULL;
}
+
+ if (ob->runtime.geometry_set_eval != NULL) {
+ BKE_geometry_set_free(ob->runtime.geometry_set_eval);
+ ob->runtime.geometry_set_eval = NULL;
+ }
}
void BKE_object_free_caches(Object *object)
@@ -1771,6 +1779,10 @@ int BKE_object_visibility(const Object *ob, const int dag_eval_mode)
visibility |= OB_VISIBLE_INSTANCES;
}
+ if (ob->runtime.geometry_set_eval != NULL) {
+ visibility |= OB_VISIBLE_INSTANCES;
+ }
+
/* Optional hiding of self if there are particles or instancers. */
if (visibility & (OB_VISIBLE_PARTICLES | OB_VISIBLE_INSTANCES)) {
switch ((eEvaluationMode)dag_eval_mode) {
@@ -4880,6 +4892,7 @@ void BKE_object_runtime_reset_on_copy(Object *object, const int UNUSED(flag))
runtime->mesh_deform_eval = NULL;
runtime->curve_cache = NULL;
runtime->object_as_temp_mesh = NULL;
+ runtime->geometry_set_eval = NULL;
}
/**
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index a1b01bce6c9..9a8c560f116 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -47,6 +47,7 @@
#include "BKE_editmesh.h"
#include "BKE_editmesh_cache.h"
#include "BKE_font.h"
+#include "BKE_geometry_set.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_lattice.h"
@@ -807,6 +808,45 @@ static const DupliGenerator gen_dupli_verts_pointcloud = {
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Instances Geometry Component Implementation
+ * \{ */
+
+static void make_duplis_instances_component(const DupliContext *ctx)
+{
+ float(*positions)[3];
+ float(*rotations)[3];
+ float(*scales)[3];
+ Object **objects;
+ const int amount = BKE_geometry_set_instances(
+ ctx->object->runtime.geometry_set_eval, &positions, &rotations, &scales, &objects);
+
+ for (int i = 0; i < amount; i++) {
+ Object *object = objects[i];
+ if (object == NULL) {
+ continue;
+ }
+ float scale_matrix[4][4];
+ size_to_mat4(scale_matrix, scales[i]);
+ float rotation_matrix[4][4];
+ eul_to_mat4(rotation_matrix, rotations[i]);
+ float matrix[4][4];
+ mul_m4_m4m4(matrix, rotation_matrix, scale_matrix);
+ copy_v3_v3(matrix[3], positions[i]);
+ mul_m4_m4_pre(matrix, ctx->object->obmat);
+
+ make_dupli(ctx, object, matrix, i);
+ make_recursive_duplis(ctx, object, matrix, i);
+ }
+}
+
+static const DupliGenerator gen_dupli_instances_component = {
+ 0,
+ make_duplis_instances_component,
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Dupli-Faces Implementation (#OB_DUPLIFACES)
* \{ */
@@ -1473,7 +1513,7 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
int transflag = ctx->object->transflag;
int restrictflag = ctx->object->restrictflag;
- if ((transflag & OB_DUPLI) == 0) {
+ if ((transflag & OB_DUPLI) == 0 && ctx->object->runtime.geometry_set_eval == NULL) {
return NULL;
}
@@ -1483,6 +1523,12 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
return NULL;
}
+ if (ctx->object->runtime.geometry_set_eval != NULL) {
+ if (BKE_geometry_set_has_instances(ctx->object->runtime.geometry_set_eval)) {
+ return &gen_dupli_instances_component;
+ }
+ }
+
if (transflag & OB_DUPLIPARTS) {
return &gen_dupli_particles;
}
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 72115db4fb8..14e049384ef 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -1198,9 +1198,6 @@ static bool foreach_object_modifier_ptcache(Object *object,
}
}
}
- else if (md->type == eModifierType_Simulation) {
- /* TODO(jacques): */
- }
}
return true;
}
diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc
index cbfb1086e8d..5f6685817b9 100644
--- a/source/blender/blenkernel/intern/pointcloud.cc
+++ b/source/blender/blenkernel/intern/pointcloud.cc
@@ -33,12 +33,14 @@
#include "BKE_anim_data.h"
#include "BKE_customdata.h"
+#include "BKE_geometry_set.hh"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_lib_remap.h"
#include "BKE_main.h"
+#include "BKE_mesh_wrapper.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_pointcloud.h"
@@ -53,8 +55,8 @@
static void pointcloud_random(PointCloud *pointcloud);
-const char *POINTCLOUD_ATTR_POSITION = "Position";
-const char *POINTCLOUD_ATTR_RADIUS = "Radius";
+const char *POINTCLOUD_ATTR_POSITION = "position";
+const char *POINTCLOUD_ATTR_RADIUS = "radius";
static void pointcloud_init_data(ID *id)
{
@@ -86,6 +88,8 @@ static void pointcloud_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_s
alloc_type,
pointcloud_dst->totpoint);
BKE_pointcloud_update_customdata_pointers(pointcloud_dst);
+
+ pointcloud_dst->batch_cache = nullptr;
}
static void pointcloud_free_data(ID *id)
@@ -230,10 +234,46 @@ void *BKE_pointcloud_add_default(Main *bmain, const char *name)
return pointcloud;
}
+PointCloud *BKE_pointcloud_new_nomain(const int totpoint)
+{
+ PointCloud *pointcloud = static_cast<PointCloud *>(BKE_libblock_alloc(
+ nullptr, ID_PT, BKE_idtype_idcode_to_name(ID_PT), LIB_ID_CREATE_LOCALIZE));
+
+ pointcloud_init_data(&pointcloud->id);
+
+ pointcloud->totpoint = totpoint;
+
+ CustomData_add_layer_named(&pointcloud->pdata,
+ CD_PROP_FLOAT,
+ CD_CALLOC,
+ nullptr,
+ pointcloud->totpoint,
+ POINTCLOUD_ATTR_RADIUS);
+
+ pointcloud->totpoint = totpoint;
+ CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint);
+ BKE_pointcloud_update_customdata_pointers(pointcloud);
+
+ return pointcloud;
+}
+
+void BKE_pointcloud_minmax(const struct PointCloud *pointcloud, float r_min[3], float r_max[3])
+{
+ float(*pointcloud_co)[3] = pointcloud->co;
+ float *pointcloud_radius = pointcloud->radius;
+ for (int a = 0; a < pointcloud->totpoint; a++) {
+ float *co = pointcloud_co[a];
+ float radius = (pointcloud_radius) ? pointcloud_radius[a] : 0.0f;
+ const float co_min[3] = {co[0] - radius, co[1] - radius, co[2] - radius};
+ const float co_max[3] = {co[0] + radius, co[1] + radius, co[2] + radius};
+ DO_MIN(co_min, r_min);
+ DO_MAX(co_max, r_max);
+ }
+}
+
BoundBox *BKE_pointcloud_boundbox_get(Object *ob)
{
BLI_assert(ob->type == OB_POINTCLOUD);
- PointCloud *pointcloud = static_cast<PointCloud *>(ob->data);
if (ob->runtime.bb != nullptr && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) {
return ob->runtime.bb;
@@ -241,23 +281,18 @@ BoundBox *BKE_pointcloud_boundbox_get(Object *ob)
if (ob->runtime.bb == nullptr) {
ob->runtime.bb = static_cast<BoundBox *>(MEM_callocN(sizeof(BoundBox), "pointcloud boundbox"));
+ }
- float min[3], max[3];
- INIT_MINMAX(min, max);
-
- float(*pointcloud_co)[3] = pointcloud->co;
- float *pointcloud_radius = pointcloud->radius;
- for (int a = 0; a < pointcloud->totpoint; a++) {
- float *co = pointcloud_co[a];
- float radius = (pointcloud_radius) ? pointcloud_radius[a] : 0.0f;
- const float co_min[3] = {co[0] - radius, co[1] - radius, co[2] - radius};
- const float co_max[3] = {co[0] + radius, co[1] + radius, co[2] + radius};
- DO_MIN(co_min, min);
- DO_MAX(co_max, max);
- }
-
- BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
+ blender::float3 min, max;
+ INIT_MINMAX(min, max);
+ if (ob->runtime.geometry_set_eval != nullptr) {
+ ob->runtime.geometry_set_eval->compute_boundbox_without_instances(&min, &max);
+ }
+ else {
+ const PointCloud *pointcloud = static_cast<PointCloud *>(ob->data);
+ BKE_pointcloud_minmax(pointcloud, min, max);
}
+ BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
return ob->runtime.bb;
}
@@ -306,13 +341,11 @@ PointCloud *BKE_pointcloud_copy_for_eval(struct PointCloud *pointcloud_src, bool
return result;
}
-static PointCloud *pointcloud_evaluate_modifiers(struct Depsgraph *depsgraph,
- struct Scene *scene,
- Object *object,
- PointCloud *pointcloud_input)
+static void pointcloud_evaluate_modifiers(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ Object *object,
+ GeometrySet &geometry_set)
{
- PointCloud *pointcloud = pointcloud_input;
-
/* Modifier evaluation modes. */
const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
@@ -332,40 +365,10 @@ static PointCloud *pointcloud_evaluate_modifiers(struct Depsgraph *depsgraph,
continue;
}
- if ((mti->type == eModifierTypeType_OnlyDeform) &&
- (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly)) {
- /* Ensure we are not modifying the input. */
- if (pointcloud == pointcloud_input) {
- pointcloud = BKE_pointcloud_copy_for_eval(pointcloud, true);
- }
-
- /* Ensure we are not overwriting referenced data. */
- CustomData_duplicate_referenced_layer_named(
- &pointcloud->pdata, CD_PROP_FLOAT3, POINTCLOUD_ATTR_POSITION, pointcloud->totpoint);
- BKE_pointcloud_update_customdata_pointers(pointcloud);
-
- /* Created deformed coordinates array on demand. */
- mti->deformVerts(md, &mectx, nullptr, pointcloud->co, pointcloud->totpoint);
- }
- else if (mti->modifyPointCloud) {
- /* Ensure we are not modifying the input. */
- if (pointcloud == pointcloud_input) {
- pointcloud = BKE_pointcloud_copy_for_eval(pointcloud, true);
- }
-
- PointCloud *pointcloud_next = mti->modifyPointCloud(md, &mectx, pointcloud);
-
- if (pointcloud_next && pointcloud_next != pointcloud) {
- /* If the modifier returned a new pointcloud, release the old one. */
- if (pointcloud != pointcloud_input) {
- BKE_id_free(nullptr, pointcloud);
- }
- pointcloud = pointcloud_next;
- }
+ if (mti->modifyPointCloud) {
+ mti->modifyPointCloud(md, &mectx, &geometry_set);
}
}
-
- return pointcloud;
}
void BKE_pointcloud_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Object *object)
@@ -375,12 +378,14 @@ void BKE_pointcloud_data_update(struct Depsgraph *depsgraph, struct Scene *scene
/* Evaluate modifiers. */
PointCloud *pointcloud = static_cast<PointCloud *>(object->data);
- PointCloud *pointcloud_eval = pointcloud_evaluate_modifiers(
- depsgraph, scene, object, pointcloud);
+ GeometrySet geometry_set = GeometrySet::create_with_pointcloud(pointcloud,
+ GeometryOwnershipType::ReadOnly);
+ pointcloud_evaluate_modifiers(depsgraph, scene, object, geometry_set);
/* Assign evaluated object. */
- const bool is_owned = (pointcloud != pointcloud_eval);
- BKE_object_eval_assign_data(object, &pointcloud_eval->id, is_owned);
+ PointCloud *dummy_pointcloud = BKE_pointcloud_new_nomain(0);
+ BKE_object_eval_assign_data(object, &dummy_pointcloud->id, true);
+ object->runtime.geometry_set_eval = new GeometrySet(geometry_set);
}
/* Draw Cache */
diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc
index 861779ec700..14e6ce63023 100644
--- a/source/blender/blenkernel/intern/simulation.cc
+++ b/source/blender/blenkernel/intern/simulation.cc
@@ -48,8 +48,8 @@
#include "BKE_pointcache.h"
#include "BKE_simulation.h"
+#include "NOD_geometry.h"
#include "NOD_node_tree_multi_function.hh"
-#include "NOD_simulation.h"
#include "BLI_map.hh"
#include "BLT_translation.h"
@@ -70,7 +70,7 @@ static void simulation_init_data(ID *id)
MEMCPY_STRUCT_AFTER(simulation, DNA_struct_default_get(Simulation), id);
- bNodeTree *ntree = ntreeAddTree(nullptr, "Simulation Nodetree", ntreeType_Simulation->idname);
+ bNodeTree *ntree = ntreeAddTree(nullptr, "Geometry Nodetree", ntreeType_Geometry->idname);
simulation->nodetree = ntree;
}