From 38af29df5c307517dfdd0803b7e00d979be7185d Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 23 Sep 2021 17:50:33 +0200 Subject: Geometry Nodes: simplify looping over attributes in geometry set This adds three new methods: * `InstancesComponent::foreach_reference_as_geometry(...)` * `GeometrySet::attribute_foreach(...)` * `GeometrySet::gather_attributes_for_propagation(...)` The goal is that these iteration primitives can be used in places where we use more specialized iterators currently. Differential Revision: https://developer.blender.org/D12613 --- source/blender/blenkernel/BKE_attribute_access.hh | 5 ++ source/blender/blenkernel/BKE_geometry_set.hh | 19 ++++++ .../blenkernel/BKE_geometry_set_instances.hh | 5 -- source/blender/blenkernel/intern/geometry_set.cc | 70 ++++++++++++++++++++++ .../blenkernel/intern/geometry_set_instances.cc | 35 +++++++++++ .../geometry/nodes/node_geo_point_distribute.cc | 1 - 6 files changed, 129 insertions(+), 6 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh index 77db479f525..da3de2f08bd 100644 --- a/source/blender/blenkernel/BKE_attribute_access.hh +++ b/source/blender/blenkernel/BKE_attribute_access.hh @@ -122,6 +122,11 @@ struct AttributeMetaData { } }; +struct AttributeKind { + AttributeDomain domain; + CustomDataType data_type; +}; + /** * Base class for the attribute initializer types described below. */ diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index 317d513dae6..a6c77c74b9e 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -25,6 +25,7 @@ #include "BLI_float3.hh" #include "BLI_float4x4.hh" +#include "BLI_function_ref.hh" #include "BLI_hash.hh" #include "BLI_map.hh" #include "BLI_set.hh" @@ -293,6 +294,21 @@ struct GeometrySet { bool owns_direct_data() const; void ensure_owns_direct_data(); + using AttributeForeachCallback = + blender::FunctionRef; + + void attribute_foreach(blender::Span component_types, + bool include_instances, + AttributeForeachCallback callback) const; + + void gather_attributes_for_propagation( + blender::Span component_types, + GeometryComponentType dst_component_type, + bool include_instances, + blender::Map &r_attributes) const; + /* Utility methods for creation. */ static GeometrySet create_with_mesh( Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned); @@ -597,6 +613,9 @@ class InstancesComponent : public GeometryComponent { int attribute_domain_size(const AttributeDomain domain) const final; + void foreach_referenced_geometry( + blender::FunctionRef callback) const; + bool is_empty() const final; bool owns_direct_data() const override; diff --git a/source/blender/blenkernel/BKE_geometry_set_instances.hh b/source/blender/blenkernel/BKE_geometry_set_instances.hh index 44a0ee30c4c..9d68d726c3a 100644 --- a/source/blender/blenkernel/BKE_geometry_set_instances.hh +++ b/source/blender/blenkernel/BKE_geometry_set_instances.hh @@ -49,11 +49,6 @@ void geometry_set_gather_instances(const GeometrySet &geometry_set, GeometrySet geometry_set_realize_mesh_for_modifier(const GeometrySet &geometry_set); GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set); -struct AttributeKind { - CustomDataType data_type; - AttributeDomain domain; -}; - /** * Add information about all the attributes on every component of the type. The resulting info * will contain the highest complexity data type and the highest priority domain among every diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index e717d289894..54e9fadf8ed 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -375,6 +375,76 @@ CurveEval *GeometrySet::get_curve_for_write() return component.get_for_write(); } +void GeometrySet::attribute_foreach(const Span component_types, + const bool include_instances, + const AttributeForeachCallback callback) const +{ + using namespace blender; + using namespace blender::bke; + for (const GeometryComponentType component_type : component_types) { + if (!this->has(component_type)) { + continue; + } + const GeometryComponent &component = *this->get_component_for_read(component_type); + component.attribute_foreach( + [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { + callback(attribute_id, meta_data, component); + return true; + }); + } + if (include_instances && this->has_instances()) { + const InstancesComponent &instances = *this->get_component_for_read(); + instances.foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) { + instance_geometry_set.attribute_foreach(component_types, include_instances, callback); + }); + } +} + +void GeometrySet::gather_attributes_for_propagation( + const Span component_types, + const GeometryComponentType dst_component_type, + bool include_instances, + blender::Map &r_attributes) const +{ + using namespace blender; + using namespace blender::bke; + /* Only needed right now to check if an attribute is built-in on this component type. + * TODO: Get rid of the dummy component. */ + const GeometryComponent *dummy_component = GeometryComponent::create(dst_component_type); + this->attribute_foreach( + component_types, + include_instances, + [&](const AttributeIDRef &attribute_id, + const AttributeMetaData &meta_data, + const GeometryComponent &component) { + if (component.attribute_is_builtin(attribute_id)) { + if (!dummy_component->attribute_is_builtin(attribute_id)) { + /* Don't propagate built-in attributes that are not built-in on the destination + * component. */ + return; + } + } + if (attribute_id.is_anonymous()) { + if (!BKE_anonymous_attribute_id_has_strong_references(&attribute_id.anonymous_id())) { + /* Don't propagate anonymous attributes that are not used anymore. */ + return; + } + } + auto add_info = [&](AttributeKind *attribute_kind) { + attribute_kind->domain = meta_data.domain; + attribute_kind->data_type = meta_data.data_type; + }; + auto modify_info = [&](AttributeKind *attribute_kind) { + attribute_kind->domain = bke::attribute_domain_highest_priority( + {attribute_kind->domain, meta_data.domain}); + attribute_kind->data_type = bke::attribute_data_type_highest_complexity( + {attribute_kind->data_type, meta_data.data_type}); + }; + r_attributes.add_or_modify(attribute_id, add_info, modify_info); + }); + delete dummy_component; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc index 9dca2c2907e..10e698c8f8a 100644 --- a/source/blender/blenkernel/intern/geometry_set_instances.cc +++ b/source/blender/blenkernel/intern/geometry_set_instances.cc @@ -14,6 +14,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "BKE_collection.h" #include "BKE_geometry_set_instances.hh" #include "BKE_material.h" #include "BKE_mesh.h" @@ -23,6 +24,7 @@ #include "BKE_spline.hh" #include "DNA_collection_types.h" +#include "DNA_layer_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" @@ -745,3 +747,36 @@ GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set) } } // namespace blender::bke + +void InstancesComponent::foreach_referenced_geometry( + blender::FunctionRef callback) const +{ + using namespace blender::bke; + for (const InstanceReference &reference : references_) { + switch (reference.type()) { + case InstanceReference::Type::Object: { + const Object &object = reference.object(); + const GeometrySet object_geometry_set = object_get_geometry_set_for_read(object); + callback(object_geometry_set); + break; + } + case InstanceReference::Type::Collection: { + Collection &collection = reference.collection(); + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (&collection, object) { + const GeometrySet object_geometry_set = object_get_geometry_set_for_read(*object); + callback(object_geometry_set); + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + break; + } + case InstanceReference::Type::GeometrySet: { + const GeometrySet &instance_geometry_set = reference.geometry_set(); + callback(instance_geometry_set); + break; + } + case InstanceReference::Type::None: { + break; + } + } + } +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc index 04b4003daed..f95b0da86ed 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc @@ -36,7 +36,6 @@ #include "node_geometry_util.hh" -using blender::bke::AttributeKind; using blender::bke::GeometryInstanceGroup; namespace blender::nodes { -- cgit v1.2.3