From b876ce2a4a4638142439a7cf265a0780491ae4cc Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Fri, 8 Jul 2022 16:16:56 +0200 Subject: Geometry Nodes: new geometry attribute API Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is accessible from RNA and C code. The second is implemented with `GeometryComponent` and is only accessible in C++ code. The second is widely used, but only being accessible through the `GeometrySet` API makes it awkward to use, and even impossible for types that don't correspond directly to a geometry component like `CurvesGeometry`. This patch adds a new attribute API, designed to replace the `GeometryComponent` attribute API now, and to eventually replace or be the basis of the other one. The basic idea is that there is an `AttributeAccessor` class that allows code to interact with a set of attributes owned by some geometry. The accessor itself has no ownership. `AttributeAccessor` is a simple type that can be passed around by value. That makes it easy to return it from functions and to store it in containers. For const-correctness, there is also a `MutableAttributeAccessor` that allows changing individual and can add or remove attributes. Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer to the owner of the attribute data. The second is a pointer to a struct with function pointers, that is similar to a virtual function table. The functions know how to access attributes on the owner. The actual attribute access for geometries is still implemented with the `AttributeProvider` pattern, which makes it easy to support different sources of attributes on a geometry and simplifies dealing with built-in attributes. There are different ways to get an attribute accessor for a geometry: * `GeometryComponent.attributes()` * `CurvesGeometry.attributes()` * `bke::mesh_attributes(const Mesh &)` * `bke::pointcloud_attributes(const PointCloud &)` All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`. Differential Revision: https://developer.blender.org/D15280 --- source/blender/blenkernel/BKE_attribute.hh | 814 ++++++++++++++++++++ source/blender/blenkernel/BKE_attribute_access.hh | 541 ------------- source/blender/blenkernel/BKE_curves.hh | 5 +- source/blender/blenkernel/BKE_geometry_set.hh | 260 +------ source/blender/blenkernel/BKE_mesh_sample.hh | 10 +- source/blender/blenkernel/BKE_spline.hh | 4 +- source/blender/blenkernel/CMakeLists.txt | 2 +- source/blender/blenkernel/intern/attribute.cc | 2 +- .../blender/blenkernel/intern/attribute_access.cc | 856 +++++---------------- .../blenkernel/intern/attribute_access_intern.hh | 266 +++++-- source/blender/blenkernel/intern/curve_eval.cc | 125 +-- .../blenkernel/intern/curve_legacy_convert.cc | 11 +- .../blenkernel/intern/curve_to_mesh_convert.cc | 72 +- .../blenkernel/intern/geometry_component_curve.cc | 230 +++--- .../blenkernel/intern/geometry_component_curves.cc | 191 ++--- .../intern/geometry_component_instances.cc | 101 ++- .../blenkernel/intern/geometry_component_mesh.cc | 212 ++--- .../intern/geometry_component_pointcloud.cc | 102 ++- source/blender/blenkernel/intern/geometry_set.cc | 41 +- source/blender/blenkernel/intern/mesh_convert.cc | 4 +- source/blender/blenkernel/intern/mesh_sample.cc | 7 +- source/blender/blenkernel/intern/spline_base.cc | 2 +- .../blender/draw/intern/draw_cache_impl_curves.cc | 15 +- source/blender/draw/intern/draw_curves.cc | 4 +- source/blender/editors/curves/intern/curves_ops.cc | 22 +- .../editors/geometry/geometry_attributes.cc | 28 +- source/blender/editors/object/object_add.cc | 4 +- source/blender/editors/object/object_modifier.cc | 9 +- .../editors/sculpt_paint/curves_sculpt_add.cc | 9 +- .../editors/sculpt_paint/curves_sculpt_density.cc | 10 +- .../editors/sculpt_paint/curves_sculpt_slide.cc | 9 +- .../editors/sculpt_paint/paint_vertex_color_ops.cc | 48 +- .../spreadsheet_data_source_geometry.cc | 33 +- .../space_spreadsheet/spreadsheet_dataset_draw.cc | 2 +- .../geometry/intern/mesh_primitive_cuboid.cc | 12 +- .../geometry/intern/mesh_to_curve_convert.cc | 22 +- .../geometry/intern/point_merge_by_distance.cc | 27 +- .../blender/geometry/intern/realize_instances.cc | 268 +++---- source/blender/geometry/intern/resample_curves.cc | 25 +- source/blender/geometry/intern/set_curve_type.cc | 36 +- source/blender/geometry/intern/subdivide_curves.cc | 58 +- .../exporter/obj_export_file_writer.cc | 5 +- source/blender/modifiers/intern/MOD_nodes.cc | 37 +- source/blender/nodes/NOD_geometry_exec.hh | 15 +- .../geometry/nodes/node_geo_accumulate_field.cc | 26 +- .../geometry/nodes/node_geo_attribute_capture.cc | 17 +- .../nodes/node_geo_attribute_domain_size.cc | 20 +- .../geometry/nodes/node_geo_attribute_statistic.cc | 16 +- .../nodes/geometry/nodes/node_geo_boolean.cc | 14 +- .../nodes/geometry/nodes/node_geo_convex_hull.cc | 18 +- .../nodes/geometry/nodes/node_geo_curve_fillet.cc | 4 +- .../nodes/node_geo_curve_primitive_star.cc | 12 +- .../nodes/geometry/nodes/node_geo_curve_reverse.cc | 4 +- .../nodes/node_geo_curve_set_handle_type.cc | 4 +- .../geometry/nodes/node_geo_curve_to_points.cc | 13 +- .../nodes/geometry/nodes/node_geo_curve_trim.cc | 4 +- .../nodes/node_geo_deform_curves_on_surface.cc | 24 +- .../geometry/nodes/node_geo_delete_geometry.cc | 42 +- .../nodes/node_geo_distribute_points_on_faces.cc | 57 +- .../nodes/geometry/nodes/node_geo_dual_mesh.cc | 11 +- .../geometry/nodes/node_geo_duplicate_elements.cc | 111 +-- .../nodes/geometry/nodes/node_geo_edge_split.cc | 4 +- .../nodes/geometry/nodes/node_geo_extrude_mesh.cc | 64 +- .../geometry/nodes/node_geo_field_at_index.cc | 2 +- .../geometry/nodes/node_geo_field_on_domain.cc | 4 +- .../nodes/geometry/nodes/node_geo_flip_faces.cc | 17 +- .../geometry/nodes/node_geo_input_curve_handles.cc | 12 +- .../nodes/node_geo_input_mesh_edge_angle.cc | 4 +- .../nodes/node_geo_input_mesh_edge_neighbors.cc | 2 +- .../nodes/node_geo_input_mesh_edge_vertices.cc | 4 +- .../nodes/node_geo_input_mesh_face_area.cc | 2 +- .../nodes/node_geo_input_mesh_face_is_planar.cc | 2 +- .../nodes/node_geo_input_mesh_face_neighbors.cc | 4 +- .../geometry/nodes/node_geo_input_mesh_island.cc | 5 +- .../geometry/nodes/node_geo_input_spline_length.cc | 2 +- .../nodes/geometry/nodes/node_geo_input_tangent.cc | 4 +- .../geometry/nodes/node_geo_instance_on_points.cc | 8 +- .../geometry/nodes/node_geo_instances_to_points.cc | 12 +- .../nodes/geometry/nodes/node_geo_join_geometry.cc | 16 +- .../geometry/nodes/node_geo_material_selection.cc | 2 +- .../geometry/nodes/node_geo_merge_by_distance.cc | 6 +- .../geometry/nodes/node_geo_mesh_primitive_cone.cc | 42 +- .../geometry/nodes/node_geo_mesh_primitive_grid.cc | 15 +- .../nodes/node_geo_mesh_primitive_uv_sphere.cc | 12 +- .../nodes/geometry/nodes/node_geo_mesh_to_curve.cc | 2 +- .../geometry/nodes/node_geo_mesh_to_points.cc | 26 +- .../nodes/geometry/nodes/node_geo_points.cc | 13 +- .../geometry/nodes/node_geo_points_to_vertices.cc | 13 +- .../geometry/nodes/node_geo_points_to_volume.cc | 7 +- .../nodes/geometry/nodes/node_geo_raycast.cc | 4 +- .../geometry/nodes/node_geo_remove_attribute.cc | 4 +- .../geometry/nodes/node_geo_set_curve_handles.cc | 10 +- .../geometry/nodes/node_geo_set_curve_radius.cc | 17 +- .../geometry/nodes/node_geo_set_curve_tilt.cc | 18 +- .../nodes/geometry/nodes/node_geo_set_id.cc | 26 +- .../geometry/nodes/node_geo_set_material_index.cc | 17 +- .../geometry/nodes/node_geo_set_point_radius.cc | 17 +- .../nodes/geometry/nodes/node_geo_set_position.cc | 52 +- .../geometry/nodes/node_geo_set_shade_smooth.cc | 18 +- .../geometry/nodes/node_geo_set_spline_cyclic.cc | 18 +- .../nodes/node_geo_set_spline_resolution.cc | 18 +- .../nodes/node_geo_store_named_attribute.cc | 25 +- .../geometry/nodes/node_geo_string_to_curves.cc | 18 +- .../geometry/nodes/node_geo_subdivision_surface.cc | 14 +- .../geometry/nodes/node_geo_transfer_attribute.cc | 10 +- .../nodes/geometry/nodes/node_geo_triangulate.cc | 4 +- .../geometry/nodes/node_geo_uv_pack_islands.cc | 6 +- .../nodes/geometry/nodes/node_geo_uv_unwrap.cc | 6 +- .../nodes/intern/geometry_nodes_eval_log.cc | 12 +- 109 files changed, 2764 insertions(+), 2809 deletions(-) create mode 100644 source/blender/blenkernel/BKE_attribute.hh delete mode 100644 source/blender/blenkernel/BKE_attribute_access.hh (limited to 'source') diff --git a/source/blender/blenkernel/BKE_attribute.hh b/source/blender/blenkernel/BKE_attribute.hh new file mode 100644 index 00000000000..b92d0d4326b --- /dev/null +++ b/source/blender/blenkernel/BKE_attribute.hh @@ -0,0 +1,814 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include "BLI_color.hh" +#include "BLI_function_ref.hh" +#include "BLI_generic_span.hh" +#include "BLI_generic_virtual_array.hh" +#include "BLI_math_vec_types.hh" +#include "BLI_set.hh" + +#include "BKE_anonymous_attribute.hh" +#include "BKE_attribute.h" + +struct Mesh; +struct PointCloud; + +namespace blender::bke { + +/** + * Identifies an attribute that is either named or anonymous. + * It does not own the identifier, so it is just a reference. + */ +class AttributeIDRef { + private: + StringRef name_; + const AnonymousAttributeID *anonymous_id_ = nullptr; + + public: + AttributeIDRef(); + AttributeIDRef(StringRef name); + AttributeIDRef(StringRefNull name); + AttributeIDRef(const char *name); + AttributeIDRef(const std::string &name); + AttributeIDRef(const AnonymousAttributeID *anonymous_id); + + operator bool() const; + uint64_t hash() const; + bool is_named() const; + bool is_anonymous() const; + StringRef name() const; + const AnonymousAttributeID &anonymous_id() const; + bool should_be_kept() const; + + friend bool operator==(const AttributeIDRef &a, const AttributeIDRef &b); + friend std::ostream &operator<<(std::ostream &stream, const AttributeIDRef &attribute_id); +}; + +/** + * Contains information about an attribute in a geometry component. + * More information can be added in the future. E.g. whether the attribute is builtin and how it is + * stored (uv map, vertex group, ...). + */ +struct AttributeMetaData { + eAttrDomain domain; + eCustomDataType data_type; + + constexpr friend bool operator==(AttributeMetaData a, AttributeMetaData b) + { + return (a.domain == b.domain) && (a.data_type == b.data_type); + } +}; + +struct AttributeKind { + eAttrDomain domain; + eCustomDataType data_type; +}; + +/** + * Base class for the attribute initializer types described below. + */ +struct AttributeInit { + enum class Type { + Default, + VArray, + MoveArray, + }; + Type type; + AttributeInit(const Type type) : type(type) + { + } +}; + +/** + * Create an attribute using the default value for the data type. + * The default values may depend on the attribute provider implementation. + */ +struct AttributeInitDefault : public AttributeInit { + AttributeInitDefault() : AttributeInit(Type::Default) + { + } +}; + +/** + * Create an attribute by copying data from an existing virtual array. The virtual array + * must have the same type as the newly created attribute. + * + * Note that this can be used to fill the new attribute with the default + */ +struct AttributeInitVArray : public AttributeInit { + blender::GVArray varray; + + AttributeInitVArray(blender::GVArray varray) + : AttributeInit(Type::VArray), varray(std::move(varray)) + { + } +}; + +/** + * Create an attribute with a by passing ownership of a pre-allocated contiguous array of data. + * Sometimes data is created before a geometry component is available. In that case, it's + * preferable to move data directly to the created attribute to avoid a new allocation and a copy. + * + * Note that this will only have a benefit for attributes that are stored directly as contiguous + * arrays, so not for some built-in attributes. + * + * The array must be allocated with MEM_*, since `attribute_try_create` will free the array if it + * can't be used directly, and that is generally how Blender expects custom data to be allocated. + */ +struct AttributeInitMove : public AttributeInit { + void *data = nullptr; + + AttributeInitMove(void *data) : AttributeInit(Type::MoveArray), data(data) + { + } +}; + +/* Returns false when the iteration should be stopped. */ +using AttributeForeachCallback = + FunctionRef; + +/** + * Result when looking up an attribute from some geometry with the intention of only reading from + * it. + */ +template struct AttributeReader { + /** + * Virtual array that provides access to the attribute data. This may be empty. + */ + VArray varray; + /** + * Domain where the attribute is stored. This also determines the size of the virtual array. + */ + eAttrDomain domain; + + operator bool() const + { + return this->varray; + } +}; + +/** + * Result when looking up an attribute from some geometry with read an write access. After writing + * to the attribute, the #finish method has to be called. This may invalidate caches based on this + * attribute. + */ +template struct AttributeWriter { + /** + * Virtual array giving read and write access to the attribute. This may be empty. + * Consider using #SpanAttributeWriter when you want to access the virtual array as a span. + */ + VMutableArray varray; + /** + * Domain where the attribute is stored on the geometry. Also determines the size of the virtual + * array. + */ + eAttrDomain domain; + /** + * A function that has to be called after the attribute has been edited. This may be empty. + */ + std::function tag_modified_fn; + + operator bool() const + { + return this->varray; + } + + /** + * Has to be called after the attribute has been modified. + */ + void finish() + { + if (this->tag_modified_fn) { + this->tag_modified_fn(); + } + } +}; + +/** + * A version of #AttributeWriter for the common case when the user of the attribute wants to write + * to a span instead of a virtual array. Since most attributes are spans internally, this can + * result in better performance and also simplifies code. + */ +template struct SpanAttributeWriter { + /** + * A span based on the virtual array that contains the attribute data. This may be empty. + */ + MutableVArraySpan span; + /** + * Domain of the attribute. Also determines the size of the span. + */ + eAttrDomain domain; + /** + * Has to be called after writing to the span. + */ + std::function tag_modified_fn; + + SpanAttributeWriter() = default; + + SpanAttributeWriter(AttributeWriter &&other, const bool copy_values_to_span) + : span(std::move(other.varray), copy_values_to_span), + domain(other.domain), + tag_modified_fn(std::move(other.tag_modified_fn)) + { + } + + operator bool() const + { + return span.varray(); + } + + /** + * Has to be called when done writing to the attribute. This makes sure that the data is copied + * to the underlying attribute if it was not stored as an array. Furthermore, this may invalidate + * other data depending on the modified attribute. + */ + void finish() + { + this->span.save(); + if (this->tag_modified_fn) { + this->tag_modified_fn(); + } + } +}; + +/** + * A generic version of #AttributeReader. + */ +struct GAttributeReader { + GVArray varray; + eAttrDomain domain; + + operator bool() const + { + return this->varray; + } + + template AttributeReader typed() const + { + return {varray.typed(), domain}; + } +}; + +/** + * A generic version of #AttributeWriter. + */ +struct GAttributeWriter { + GVMutableArray varray; + eAttrDomain domain; + std::function tag_modified_fn; + + operator bool() const + { + return this->varray; + } + + void finish() + { + if (this->tag_modified_fn) { + this->tag_modified_fn(); + } + } + + template AttributeWriter typed() const + { + return {varray.typed(), domain, tag_modified_fn}; + } +}; + +/** + * A generic version of #SpanAttributeWriter. + */ +struct GSpanAttributeWriter { + GMutableVArraySpan span; + eAttrDomain domain; + std::function tag_modified_fn; + + GSpanAttributeWriter() = default; + + GSpanAttributeWriter(GAttributeWriter &&other, const bool copy_values_to_span) + : span(std::move(other.varray), copy_values_to_span), + domain(other.domain), + tag_modified_fn(std::move(other.tag_modified_fn)) + { + } + + operator bool() const + { + return span.varray(); + } + + void finish() + { + this->span.save(); + if (this->tag_modified_fn) { + this->tag_modified_fn(); + } + } +}; + +/** + * Core functions which make up the attribute API. They should not be called directly, but through + * #AttributesAccessor or #MutableAttributesAccessor. + * + * This is similar to a virtual function table. A struct of function pointers is used instead, + * because this way the attribute accessors can be trivial and can be passed around by value. This + * makes it easy to return the attribute accessor for a geometry from a function. + */ +struct AttributeAccessorFunctions { + bool (*contains)(const void *owner, const AttributeIDRef &attribute_id); + std::optional (*lookup_meta_data)(const void *owner, + const AttributeIDRef &attribute_id); + bool (*domain_supported)(const void *owner, eAttrDomain domain); + int (*domain_size)(const void *owner, eAttrDomain domain); + bool (*is_builtin)(const void *owner, const AttributeIDRef &attribute_id); + GAttributeReader (*lookup)(const void *owner, const AttributeIDRef &attribute_id); + GVArray (*adapt_domain)(const void *owner, + const GVArray &varray, + eAttrDomain from_domain, + eAttrDomain to_domain); + bool (*for_all)(const void *owner, + FunctionRef fn); + + GAttributeWriter (*lookup_for_write)(void *owner, const AttributeIDRef &attribute_id); + bool (*remove)(void *owner, const AttributeIDRef &attribute_id); + bool (*add)(void *owner, + const AttributeIDRef &attribute_id, + eAttrDomain domain, + eCustomDataType data_type, + const AttributeInit &initializer); +}; + +/** + * Provides read-only access to the set of attributes on some geometry. + * + * Note, this does not own the attributes. When the owner is freed, it is invalid to access its + * attributes. + */ +class AttributeAccessor { + protected: + /** + * The data that actually owns the attributes, for example, a pointer to a #Mesh or #PointCloud + * Most commonly this is a pointer to a #Mesh or #PointCloud. + * Under some circumstances this can be null. In that case most methods can't be used. Just e.g. + * the #domain_size method works and returns 0 for every domain. + * + * \note This class cannot modify the owner's attributes, but the pointer is still non-const, so + * this class can be a base class for the mutable version. + */ + void *owner_; + /** + * Functions that know how to access the attributes stored in the owner above. + */ + const AttributeAccessorFunctions *fn_; + + public: + AttributeAccessor(const void *owner, const AttributeAccessorFunctions &fn) + : owner_(const_cast(owner)), fn_(&fn) + { + } + + /** + * \return True, when the attribute is available. + */ + bool contains(const AttributeIDRef &attribute_id) const + { + return fn_->contains(owner_, attribute_id); + } + + /** + * \return Information about the attribute if it exists. + */ + std::optional lookup_meta_data(const AttributeIDRef &attribute_id) const + { + return fn_->lookup_meta_data(owner_, attribute_id); + } + + /** + * \return True, when attributes can exist on that domain. + */ + bool domain_supported(const eAttrDomain domain) const + { + return fn_->domain_supported(owner_, domain); + } + + /** + * \return Number of elements in the given domain. + */ + int domain_size(const eAttrDomain domain) const + { + return fn_->domain_size(owner_, domain); + } + + /** + * \return True, when the attribute has a special meaning for Blender and can't be used for + * arbitrary things. + */ + bool is_builtin(const AttributeIDRef &attribute_id) const + { + return fn_->is_builtin(owner_, attribute_id); + } + + /** + * Get read-only access to the attribute. If the attribute does not exist, the return value is + * empty. + */ + GAttributeReader lookup(const AttributeIDRef &attribute_id) const + { + return fn_->lookup(owner_, attribute_id); + } + + /** + * Get read-only access to the attribute. If necessary, the attribute is interpolated to the + * given domain, and converted to the given type, in that order. The result may be empty. + */ + GVArray lookup(const AttributeIDRef &attribute_id, + const std::optional domain, + const std::optional data_type) const; + + /** + * Get read-only access to the attribute whereby the attribute is interpolated to the given + * domain. The result may be empty. + */ + GVArray lookup(const AttributeIDRef &attribute_id, const eAttrDomain domain) const + { + return this->lookup(attribute_id, domain, std::nullopt); + } + + /** + * Get read-only access to the attribute whereby the attribute is converted to the given type. + * The result may be empty. + */ + GVArray lookup(const AttributeIDRef &attribute_id, const eCustomDataType data_type) const + { + return this->lookup(attribute_id, std::nullopt, data_type); + } + + /** + * Get read-only access to the attribute. If necessary, the attribute is interpolated to the + * given domain and then converted to the given type, in that order. The result may be empty. + */ + template + VArray lookup(const AttributeIDRef &attribute_id, + const std::optional domain = std::nullopt) const + { + const CPPType &cpp_type = CPPType::get(); + const eCustomDataType data_type = cpp_type_to_custom_data_type(cpp_type); + return this->lookup(attribute_id, domain, data_type).typed(); + } + + /** + * Get read-only access to the attribute. If necessary, the attribute is interpolated to the + * given domain and then converted to the given data type, in that order. + * If the attribute does not exist, a virtual array with the given default value is returned. + * If the passed in default value is null, the default value of the type is used (generally 0). + */ + GVArray lookup_or_default(const AttributeIDRef &attribute_id, + const eAttrDomain domain, + const eCustomDataType data_type, + const void *default_value = nullptr) const; + + /** + * Same as the generic version above, but should be used when the type is known at compile time. + */ + template + VArray lookup_or_default(const AttributeIDRef &attribute_id, + const eAttrDomain domain, + const T &default_value) const + { + if (VArray varray = this->lookup(attribute_id, domain)) { + return varray; + } + return VArray::ForSingle(default_value, this->domain_size(domain)); + } + + /** + * Interpolate data from one domain to another. + */ + GVArray adapt_domain(const GVArray &varray, + const eAttrDomain from_domain, + const eAttrDomain to_domain) const + { + return fn_->adapt_domain(owner_, varray, from_domain, to_domain); + } + + /** + * Interpolate data from one domain to another. + */ + template + VArray adapt_domain(const VArray &varray, + const eAttrDomain from_domain, + const eAttrDomain to_domain) const + { + return this->adapt_domain(GVArray(varray), from_domain, to_domain).typed(); + } + + /** + * Run the provided function for every attribute. + */ + bool for_all(const AttributeForeachCallback fn) const + { + return fn_->for_all(owner_, fn); + } + + /** + * Get a set of all attributes. + */ + Set all_ids() const; +}; + +/** + * Extends #AttributeAccessor with methods that allow modifying individual attributes as well as + * the set of attributes. + */ +class MutableAttributeAccessor : public AttributeAccessor { + public: + MutableAttributeAccessor(void *owner, const AttributeAccessorFunctions &fn) + : AttributeAccessor(owner, fn) + { + } + + /** + * Get a writable attribute or none if it does not exist. + * Make sure to call #finish after changes are done. + */ + GAttributeWriter lookup_for_write(const AttributeIDRef &attribute_id) + { + return fn_->lookup_for_write(owner_, attribute_id); + } + + /** + * Get a writable attribute or non if it does not exist. + * Make sure to call #finish after changes are done. + */ + template AttributeWriter lookup_for_write(const AttributeIDRef &attribute_id) + { + GAttributeWriter attribute = this->lookup_for_write(attribute_id); + if (!attribute) { + return {}; + } + if (!attribute.varray.type().is()) { + return {}; + } + return attribute.typed(); + } + + /** + * Create a new attribute. + * \return True, when a new attribute has been created. False, when it's not possible to create + * this attribute or there is already an attribute with that id. + */ + bool add(const AttributeIDRef &attribute_id, + const eAttrDomain domain, + const eCustomDataType data_type, + const AttributeInit &initializer) + { + return fn_->add(owner_, attribute_id, domain, data_type, initializer); + } + + /** + * Find an attribute with the given id, domain and data type. If it does not exist, create a new + * attribute. If the attribute does not exist and can't be created (e.g. because it already + * exists on a different domain or with a different type), none is returned. + */ + GAttributeWriter lookup_or_add_for_write( + const AttributeIDRef &attribute_id, + const eAttrDomain domain, + const eCustomDataType data_type, + const AttributeInit &initializer = AttributeInitDefault()); + + /** + * Same as above, but returns a type that makes it easier to work with the attribute as a span. + * If the caller newly initializes the attribute, it's better to use + * #lookup_or_add_for_write_only_span. + */ + GSpanAttributeWriter lookup_or_add_for_write_span( + const AttributeIDRef &attribute_id, + const eAttrDomain domain, + const eCustomDataType data_type, + const AttributeInit &initializer = AttributeInitDefault()); + + /** + * Same as above, but should be used when the type is known at compile time. + */ + template + AttributeWriter lookup_or_add_for_write( + const AttributeIDRef &attribute_id, + const eAttrDomain domain, + const AttributeInit &initializer = AttributeInitDefault()) + { + const CPPType &cpp_type = CPPType::get(); + const eCustomDataType data_type = cpp_type_to_custom_data_type(cpp_type); + return this->lookup_or_add_for_write(attribute_id, domain, data_type, initializer).typed(); + } + + /** + * Same as above, but should be used when the type is known at compile time. + */ + template + SpanAttributeWriter lookup_or_add_for_write_span( + const AttributeIDRef &attribute_id, + const eAttrDomain domain, + const AttributeInit &initializer = AttributeInitDefault()) + { + AttributeWriter attribute = this->lookup_or_add_for_write( + attribute_id, domain, initializer); + if (attribute) { + return SpanAttributeWriter{std::move(attribute), true}; + } + return {}; + } + + /** + * Find an attribute with the given id, domain and data type. If it does not exist, create a new + * attribute. If the attribute does not exist and can't be created, none is returned. + * + * The "only" in the name indicates that the caller should not read existing values from the + * span. If the attribute is not stored as span internally, the existing values won't be copied + * over to the span. + */ + GSpanAttributeWriter lookup_or_add_for_write_only_span(const AttributeIDRef &attribute_id, + const eAttrDomain domain, + const eCustomDataType data_type); + + /** + * Same as above, but should be used when the type is known at compile time. + */ + template + SpanAttributeWriter lookup_or_add_for_write_only_span(const AttributeIDRef &attribute_id, + const eAttrDomain domain) + { + AttributeWriter attribute = this->lookup_or_add_for_write(attribute_id, domain); + if (attribute) { + return SpanAttributeWriter{std::move(attribute), false}; + } + return {}; + } + + /** + * Remove an attribute. + * \return True, when the attribute has been deleted. False, when it's not possible to delete + * this attribute or if there is no attribute with that id. + */ + bool remove(const AttributeIDRef &attribute_id) + { + return fn_->remove(owner_, attribute_id); + } + + /** + * Remove all anonymous attributes. + */ + void remove_anonymous(); +}; + +bool allow_procedural_attribute_access(StringRef attribute_name); +extern const char *no_procedural_access_message; + +eCustomDataType attribute_data_type_highest_complexity(Span data_types); +/** + * Domains with a higher "information density" have a higher priority, + * in order to choose a domain that will not lose data through domain conversion. + */ +eAttrDomain attribute_domain_highest_priority(Span domains); + +/** + * A basic container around DNA CustomData so that its users + * don't have to implement special copy and move constructors. + */ +class CustomDataAttributes { + /** + * #CustomData needs a size to be freed, and unfortunately it isn't stored in the struct + * itself, so keep track of the size here so this class can implement its own destructor. + * If the implementation of the attribute storage changes, this could be removed. + */ + int size_; + + public: + CustomData data; + + CustomDataAttributes(); + ~CustomDataAttributes(); + CustomDataAttributes(const CustomDataAttributes &other); + CustomDataAttributes(CustomDataAttributes &&other); + CustomDataAttributes &operator=(const CustomDataAttributes &other); + + void reallocate(int size); + + void clear(); + + std::optional get_for_read(const AttributeIDRef &attribute_id) const; + + /** + * Return a virtual array for a stored attribute, or a single value virtual array with the + * default value if the attribute doesn't exist. If no default value is provided, the default + * value for the type will be used. + */ + blender::GVArray get_for_read(const AttributeIDRef &attribute_id, + eCustomDataType data_type, + const void *default_value) const; + + template + blender::VArray get_for_read(const AttributeIDRef &attribute_id, const T &default_value) const + { + const blender::CPPType &cpp_type = blender::CPPType::get(); + const eCustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type); + GVArray varray = this->get_for_read(attribute_id, type, &default_value); + return varray.typed(); + } + + std::optional get_for_write(const AttributeIDRef &attribute_id); + bool create(const AttributeIDRef &attribute_id, eCustomDataType data_type); + bool create_by_move(const AttributeIDRef &attribute_id, eCustomDataType data_type, void *buffer); + bool remove(const AttributeIDRef &attribute_id); + + /** + * Change the order of the attributes to match the order of IDs in the argument. + */ + void reorder(Span new_order); + + bool foreach_attribute(const AttributeForeachCallback callback, eAttrDomain domain) const; +}; + +AttributeAccessor mesh_attributes(const Mesh &mesh); +MutableAttributeAccessor mesh_attributes_for_write(Mesh &mesh); + +AttributeAccessor pointcloud_attributes(const PointCloud &pointcloud); +MutableAttributeAccessor pointcloud_attributes_for_write(PointCloud &pointcloud); + +/* -------------------------------------------------------------------- */ +/** \name #AttributeIDRef Inline Methods + * \{ */ + +inline AttributeIDRef::AttributeIDRef() = default; + +inline AttributeIDRef::AttributeIDRef(StringRef name) : name_(name) +{ +} + +inline AttributeIDRef::AttributeIDRef(StringRefNull name) : name_(name) +{ +} + +inline AttributeIDRef::AttributeIDRef(const char *name) : name_(name) +{ +} + +inline AttributeIDRef::AttributeIDRef(const std::string &name) : name_(name) +{ +} + +/* The anonymous id is only borrowed, the caller has to keep a reference to it. */ +inline AttributeIDRef::AttributeIDRef(const AnonymousAttributeID *anonymous_id) + : anonymous_id_(anonymous_id) +{ +} + +inline bool operator==(const AttributeIDRef &a, const AttributeIDRef &b) +{ + return a.anonymous_id_ == b.anonymous_id_ && a.name_ == b.name_; +} + +inline AttributeIDRef::operator bool() const +{ + return this->is_named() || this->is_anonymous(); +} + +inline uint64_t AttributeIDRef::hash() const +{ + return get_default_hash_2(name_, anonymous_id_); +} + +inline bool AttributeIDRef::is_named() const +{ + return !name_.is_empty(); +} + +inline bool AttributeIDRef::is_anonymous() const +{ + return anonymous_id_ != nullptr; +} + +inline StringRef AttributeIDRef::name() const +{ + BLI_assert(this->is_named()); + return name_; +} + +inline const AnonymousAttributeID &AttributeIDRef::anonymous_id() const +{ + BLI_assert(this->is_anonymous()); + return *anonymous_id_; +} + +/** + * \return True if the attribute should not be removed automatically as an optimization during + * processing or copying. Anonymous attributes can be removed when they no longer have any + * references. + */ +inline bool AttributeIDRef::should_be_kept() const +{ + return this->is_named() || BKE_anonymous_attribute_id_has_strong_references(anonymous_id_); +} + +} // namespace blender::bke diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh deleted file mode 100644 index 9648b5b7cde..00000000000 --- a/source/blender/blenkernel/BKE_attribute_access.hh +++ /dev/null @@ -1,541 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#pragma once - -#include - -#include "BKE_anonymous_attribute.hh" -#include "BKE_attribute.h" - -#include "BLI_color.hh" -#include "BLI_function_ref.hh" -#include "BLI_generic_span.hh" -#include "BLI_generic_virtual_array.hh" -#include "BLI_math_vec_types.hh" - -/** - * This file defines classes that help to provide access to attribute data on a #GeometryComponent. - * The API for retrieving attributes is defined in `BKE_geometry_set.hh`, but this comment has some - * general comments about the system. - * - * Attributes are stored in geometry data, though they can also be stored in instances. Their - * storage is often tied to `CustomData`, which is a system to store "layers" of data with specific - * types and names. However, since `CustomData` was added to Blender before attributes were - * conceptualized, it combines the "legacy" style of task-specific attribute types with generic - * types like "Float". The attribute API here only provides access to generic types. - * - * Attributes are retrieved from geometry components by providing an "id" (#AttributeIDRef). This - * is most commonly just an attribute name. The attribute API on geometry components has some more - * advanced capabilities: - * 1. Read-only access: With a `const` geometry component, an attribute on the geometry cannot be - * modified, so the `for_write` and `for_output` versions of the API are not available. This is - * extremely important for writing coherent bug-free code. When an attribute is retrieved with - * write access, via #WriteAttributeLookup or #OutputAttribute, the geometry component must be - * tagged to clear caches that depend on the changed data. - * 2. Domain interpolation: When retrieving an attribute, a domain (#eAttrDomain) can be - * provided. If the attribute is stored on a different domain and conversion is possible, a - * version of the data interpolated to the requested domain will be provided. These conversions - * are implemented in each #GeometryComponent by `attribute_try_adapt_domain_impl`. - * 3. Implicit type conversion: In addition to interpolating domains, attribute types can be - * converted, using the conversions in `BKE_type_conversions.hh`. The #VArray / #GVArray system - * makes it possible to only convert necessary indices on-demand. - * 4. Anonymous attributes: The "id" used to look up an attribute can also be an anonymous - * attribute reference. Currently anonymous attributes are only used in geometry nodes. - * 5. Abstracted storage: Since the data returned from the API is usually a virtual array, - * it doesn't have to be stored contiguously (even though that is generally preferred). This - * allows accessing "legacy" attributes like `material_index`, which is stored in `MPoly`. - */ - -namespace blender::bke { - -/** - * Identifies an attribute that is either named or anonymous. - * It does not own the identifier, so it is just a reference. - */ -class AttributeIDRef { - private: - StringRef name_; - const AnonymousAttributeID *anonymous_id_ = nullptr; - - public: - AttributeIDRef(); - AttributeIDRef(StringRef name); - AttributeIDRef(StringRefNull name); - AttributeIDRef(const char *name); - AttributeIDRef(const std::string &name); - AttributeIDRef(const AnonymousAttributeID *anonymous_id); - - operator bool() const; - uint64_t hash() const; - bool is_named() const; - bool is_anonymous() const; - StringRef name() const; - const AnonymousAttributeID &anonymous_id() const; - bool should_be_kept() const; - - friend bool operator==(const AttributeIDRef &a, const AttributeIDRef &b); - friend std::ostream &operator<<(std::ostream &stream, const AttributeIDRef &attribute_id); -}; - -bool allow_procedural_attribute_access(StringRef attribute_name); -extern const char *no_procedural_access_message; - -} // namespace blender::bke - -/** - * Contains information about an attribute in a geometry component. - * More information can be added in the future. E.g. whether the attribute is builtin and how it is - * stored (uv map, vertex group, ...). - */ -struct AttributeMetaData { - eAttrDomain domain; - eCustomDataType data_type; - - constexpr friend bool operator==(AttributeMetaData a, AttributeMetaData b) - { - return (a.domain == b.domain) && (a.data_type == b.data_type); - } -}; - -struct AttributeKind { - eAttrDomain domain; - eCustomDataType data_type; -}; - -/** - * Base class for the attribute initializer types described below. - */ -struct AttributeInit { - enum class Type { - Default, - VArray, - MoveArray, - }; - Type type; - AttributeInit(const Type type) : type(type) - { - } -}; - -/** - * Create an attribute using the default value for the data type. - * The default values may depend on the attribute provider implementation. - */ -struct AttributeInitDefault : public AttributeInit { - AttributeInitDefault() : AttributeInit(Type::Default) - { - } -}; - -/** - * Create an attribute by copying data from an existing virtual array. The virtual array - * must have the same type as the newly created attribute. - * - * Note that this can be used to fill the new attribute with the default - */ -struct AttributeInitVArray : public AttributeInit { - blender::GVArray varray; - - AttributeInitVArray(blender::GVArray varray) - : AttributeInit(Type::VArray), varray(std::move(varray)) - { - } -}; - -/** - * Create an attribute with a by passing ownership of a pre-allocated contiguous array of data. - * Sometimes data is created before a geometry component is available. In that case, it's - * preferable to move data directly to the created attribute to avoid a new allocation and a copy. - * - * Note that this will only have a benefit for attributes that are stored directly as contiguous - * arrays, so not for some built-in attributes. - * - * The array must be allocated with MEM_*, since `attribute_try_create` will free the array if it - * can't be used directly, and that is generally how Blender expects custom data to be allocated. - */ -struct AttributeInitMove : public AttributeInit { - void *data = nullptr; - - AttributeInitMove(void *data) : AttributeInit(Type::MoveArray), data(data) - { - } -}; - -/* Returns false when the iteration should be stopped. */ -using AttributeForeachCallback = blender::FunctionRef; - -namespace blender::bke { - -eCustomDataType attribute_data_type_highest_complexity(Span data_types); -/** - * Domains with a higher "information density" have a higher priority, - * in order to choose a domain that will not lose data through domain conversion. - */ -eAttrDomain attribute_domain_highest_priority(Span domains); - -/** - * Used when looking up a "plain attribute" based on a name for reading from it. - */ -struct ReadAttributeLookup { - /* The virtual array that is used to read from this attribute. */ - GVArray varray; - /* Domain the attribute lives on in the geometry. */ - eAttrDomain domain; - - /* Convenience function to check if the attribute has been found. */ - operator bool() const - { - return this->varray; - } -}; - -/** - * Used when looking up a "plain attribute" based on a name for reading from it and writing to it. - */ -struct WriteAttributeLookup { - /** The virtual array that is used to read from and write to the attribute. */ - GVMutableArray varray; - /** Domain the attributes lives on in the geometry component. */ - eAttrDomain domain; - /** - * Call this after changing the attribute to invalidate caches that depend on this attribute. - * \note Do not call this after the component the attribute is from has been destructed. - */ - std::function tag_modified_fn; - - /* Convenience function to check if the attribute has been found. */ - operator bool() const - { - return this->varray; - } -}; - -/** - * An output attribute allows writing to an attribute (and optionally reading as well). It adds - * some convenience features on top of `GVMutableArray` that are very commonly used. - * - * Supported convenience features: - * - Implicit type conversion when writing to builtin attributes. - * - Supports simple access to a span containing the attribute values (that avoids the use of - * MutableVArraySpan in many cases). - * - An output attribute can live side by side with an existing attribute with a different domain - * or data type. The old attribute will only be overwritten when the #save function is called. - * - * \note The lifetime of an output attribute should not be longer than the lifetime of the - * geometry component it comes from, since it can keep a reference to the component for use in - * the #save method. - */ -class OutputAttribute { - public: - using SaveFn = std::function; - - private: - GVMutableArray varray_; - eAttrDomain domain_ = ATTR_DOMAIN_AUTO; - SaveFn save_; - std::unique_ptr optional_span_varray_; - bool ignore_old_values_ = false; - bool save_has_been_called_ = false; - - public: - OutputAttribute(); - OutputAttribute(OutputAttribute &&other); - OutputAttribute(GVMutableArray varray, eAttrDomain domain, SaveFn save, bool ignore_old_values); - - ~OutputAttribute(); - - operator bool() const; - - GVMutableArray &operator*(); - GVMutableArray *operator->(); - GVMutableArray &varray(); - eAttrDomain domain() const; - const CPPType &cpp_type() const; - eCustomDataType custom_data_type() const; - - GMutableSpan as_span(); - template MutableSpan as_span(); - - void save(); -}; - -/** - * Same as OutputAttribute, but should be used when the data type is known at compile time. - */ -template class OutputAttribute_Typed { - private: - OutputAttribute attribute_; - VMutableArray varray_; - - public: - OutputAttribute_Typed(); - OutputAttribute_Typed(OutputAttribute attribute) : attribute_(std::move(attribute)) - { - if (attribute_) { - varray_ = attribute_.varray().template typed(); - } - } - - OutputAttribute_Typed(OutputAttribute_Typed &&other); - ~OutputAttribute_Typed(); - - OutputAttribute_Typed &operator=(OutputAttribute_Typed &&other) - { - if (this == &other) { - return *this; - } - this->~OutputAttribute_Typed(); - new (this) OutputAttribute_Typed(std::move(other)); - return *this; - } - - operator bool() const - { - return varray_; - } - - VMutableArray &operator*() - { - return varray_; - } - - VMutableArray *operator->() - { - return &varray_; - } - - VMutableArray &varray() - { - return varray_; - } - - eAttrDomain domain() const - { - return attribute_.domain(); - } - - const CPPType &cpp_type() const - { - return CPPType::get(); - } - - eCustomDataType custom_data_type() const - { - return cpp_type_to_custom_data_type(this->cpp_type()); - } - - MutableSpan as_span() - { - return attribute_.as_span(); - } - - void save() - { - attribute_.save(); - } -}; - -/* These are not defined in the class directly, because when defining them there, the external - * template instantiation does not work, resulting in longer compile times. */ -template inline OutputAttribute_Typed::OutputAttribute_Typed() = default; -template -inline OutputAttribute_Typed::OutputAttribute_Typed(OutputAttribute_Typed &&other) = default; -template inline OutputAttribute_Typed::~OutputAttribute_Typed() = default; - -/** - * A basic container around DNA CustomData so that its users - * don't have to implement special copy and move constructors. - */ -class CustomDataAttributes { - /** - * #CustomData needs a size to be freed, and unfortunately it isn't stored in the struct - * itself, so keep track of the size here so this class can implement its own destructor. - * If the implementation of the attribute storage changes, this could be removed. - */ - int size_; - - public: - CustomData data; - - CustomDataAttributes(); - ~CustomDataAttributes(); - CustomDataAttributes(const CustomDataAttributes &other); - CustomDataAttributes(CustomDataAttributes &&other); - CustomDataAttributes &operator=(const CustomDataAttributes &other); - - void reallocate(int size); - - void clear(); - - std::optional get_for_read(const AttributeIDRef &attribute_id) const; - - /** - * Return a virtual array for a stored attribute, or a single value virtual array with the - * default value if the attribute doesn't exist. If no default value is provided, the default - * value for the type will be used. - */ - blender::GVArray get_for_read(const AttributeIDRef &attribute_id, - eCustomDataType data_type, - const void *default_value) const; - - template - blender::VArray get_for_read(const AttributeIDRef &attribute_id, const T &default_value) const - { - const blender::CPPType &cpp_type = blender::CPPType::get(); - const eCustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type); - GVArray varray = this->get_for_read(attribute_id, type, &default_value); - return varray.typed(); - } - - std::optional get_for_write(const AttributeIDRef &attribute_id); - bool create(const AttributeIDRef &attribute_id, eCustomDataType data_type); - bool create_by_move(const AttributeIDRef &attribute_id, eCustomDataType data_type, void *buffer); - bool remove(const AttributeIDRef &attribute_id); - - /** - * Change the order of the attributes to match the order of IDs in the argument. - */ - void reorder(Span new_order); - - bool foreach_attribute(const AttributeForeachCallback callback, eAttrDomain domain) const; -}; - -/* -------------------------------------------------------------------- */ -/** \name #AttributeIDRef Inline Methods - * \{ */ - -inline AttributeIDRef::AttributeIDRef() = default; - -inline AttributeIDRef::AttributeIDRef(StringRef name) : name_(name) -{ -} - -inline AttributeIDRef::AttributeIDRef(StringRefNull name) : name_(name) -{ -} - -inline AttributeIDRef::AttributeIDRef(const char *name) : name_(name) -{ -} - -inline AttributeIDRef::AttributeIDRef(const std::string &name) : name_(name) -{ -} - -/* The anonymous id is only borrowed, the caller has to keep a reference to it. */ -inline AttributeIDRef::AttributeIDRef(const AnonymousAttributeID *anonymous_id) - : anonymous_id_(anonymous_id) -{ -} - -inline bool operator==(const AttributeIDRef &a, const AttributeIDRef &b) -{ - return a.anonymous_id_ == b.anonymous_id_ && a.name_ == b.name_; -} - -inline AttributeIDRef::operator bool() const -{ - return this->is_named() || this->is_anonymous(); -} - -inline uint64_t AttributeIDRef::hash() const -{ - return get_default_hash_2(name_, anonymous_id_); -} - -inline bool AttributeIDRef::is_named() const -{ - return !name_.is_empty(); -} - -inline bool AttributeIDRef::is_anonymous() const -{ - return anonymous_id_ != nullptr; -} - -inline StringRef AttributeIDRef::name() const -{ - BLI_assert(this->is_named()); - return name_; -} - -inline const AnonymousAttributeID &AttributeIDRef::anonymous_id() const -{ - BLI_assert(this->is_anonymous()); - return *anonymous_id_; -} - -/** - * \return True if the attribute should not be removed automatically as an optimization during - * processing or copying. Anonymous attributes can be removed when they no longer have any - * references. - */ -inline bool AttributeIDRef::should_be_kept() const -{ - return this->is_named() || BKE_anonymous_attribute_id_has_strong_references(anonymous_id_); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name #OutputAttribute Inline Methods - * \{ */ - -inline OutputAttribute::OutputAttribute() = default; -inline OutputAttribute::OutputAttribute(OutputAttribute &&other) = default; - -inline OutputAttribute::OutputAttribute(GVMutableArray varray, - eAttrDomain domain, - SaveFn save, - const bool ignore_old_values) - : varray_(std::move(varray)), - domain_(domain), - save_(std::move(save)), - ignore_old_values_(ignore_old_values) -{ -} - -inline OutputAttribute::operator bool() const -{ - return varray_; -} - -inline GVMutableArray &OutputAttribute::operator*() -{ - return varray_; -} - -inline GVMutableArray *OutputAttribute::operator->() -{ - return &varray_; -} - -inline GVMutableArray &OutputAttribute::varray() -{ - return varray_; -} - -inline eAttrDomain OutputAttribute::domain() const -{ - return domain_; -} - -inline const CPPType &OutputAttribute::cpp_type() const -{ - return varray_.type(); -} - -inline eCustomDataType OutputAttribute::custom_data_type() const -{ - return cpp_type_to_custom_data_type(this->cpp_type()); -} - -template inline MutableSpan OutputAttribute::as_span() -{ - return this->as_span().typed(); -} - -/** \} */ - -} // namespace blender::bke diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh index 3e00dc78b74..fb97e52f6da 100644 --- a/source/blender/blenkernel/BKE_curves.hh +++ b/source/blender/blenkernel/BKE_curves.hh @@ -20,7 +20,7 @@ #include "BLI_vector.hh" #include "BLI_virtual_array.hh" -#include "BKE_attribute_access.hh" +#include "BKE_attribute.hh" namespace blender::bke { @@ -401,6 +401,9 @@ class CurvesGeometry : public ::CurvesGeometry { */ void remove_attributes_based_on_types(); + AttributeAccessor attributes() const; + MutableAttributeAccessor attributes_for_write(); + /* -------------------------------------------------------------------- * Attributes. */ diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index 1d4291473bb..4108e2f7e2e 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -8,6 +8,7 @@ #include #include +#include #include "BLI_float4x4.hh" #include "BLI_function_ref.hh" @@ -19,7 +20,7 @@ #include "BLI_vector_set.hh" #include "BKE_anonymous_attribute.hh" -#include "BKE_attribute_access.hh" +#include "BKE_attribute.hh" #include "BKE_geometry_set.h" struct Curves; @@ -63,6 +64,15 @@ class GeometryComponent { virtual ~GeometryComponent() = default; static GeometryComponent *create(GeometryComponentType component_type); + int attribute_domain_size(eAttrDomain domain) const; + + /** + * Get access to the attributes in this geometry component. May return none if the geometry does + * not support the attribute system. + */ + virtual std::optional attributes() const; + virtual std::optional attributes_for_write(); + /* The returned component should be of the same type as the type this is called on. */ virtual GeometryComponent *copy() const = 0; @@ -78,203 +88,7 @@ class GeometryComponent { GeometryComponentType type() const; - /** - * Return true when any attribute with this name exists, including built in attributes. - */ - bool attribute_exists(const blender::bke::AttributeIDRef &attribute_id) const; - - /** - * Return the data type and domain of an attribute with the given name if it exists. - */ - std::optional attribute_get_meta_data( - const blender::bke::AttributeIDRef &attribute_id) const; - - /** - * Return true when the geometry component supports this attribute domain. - * \note Conceptually this function is static, the result is always the same for different - * instances of the same geometry component type. - */ - bool attribute_domain_supported(eAttrDomain domain) const; - /** - * Return the length of a specific domain, or 0 if the domain is not supported. - */ - virtual int attribute_domain_num(eAttrDomain domain) const; - - /** - * Return true if the attribute name corresponds to a built-in attribute with a hardcoded domain - * and data type. - */ - bool attribute_is_builtin(const blender::StringRef attribute_name) const; - bool attribute_is_builtin(const blender::bke::AttributeIDRef &attribute_id) const; - - /** - * Get read-only access to an attribute with the given name or id, on the highest priority domain - * if there is a name collision. - * \return null if the attribute does not exist. - */ - blender::bke::ReadAttributeLookup attribute_try_get_for_read( - const blender::bke::AttributeIDRef &attribute_id) const; - - /** - * Get read and write access to an attribute with the given name or id, on the highest priority - * domain if there is a name collision. - * \note #WriteAttributeLookup.tag_modified_fn must be called after modifying data. - * \return null if the attribute does not exist - */ - blender::bke::WriteAttributeLookup attribute_try_get_for_write( - const blender::bke::AttributeIDRef &attribute_id); - - /** - * Get a read-only attribute for the domain based on the given attribute. This can be used to - * interpolate from one domain to another. - * \return null if the interpolation is not implemented. - */ - blender::GVArray attribute_try_adapt_domain(const blender::GVArray &varray, - const eAttrDomain from_domain, - const eAttrDomain to_domain) const - { - return this->attribute_try_adapt_domain_impl(varray, from_domain, to_domain); - } - /* Use instead of the method above when the type is known at compile time for type safety. */ - template - blender::VArray attribute_try_adapt_domain(const blender::VArray &varray, - const eAttrDomain from_domain, - const eAttrDomain to_domain) const - { - return this->attribute_try_adapt_domain_impl(varray, from_domain, to_domain) - .template typed(); - } - - /** Returns true when the attribute has been deleted. */ - bool attribute_try_delete(const blender::bke::AttributeIDRef &attribute_id); - - /** - * Remove any anonymous attributes on the geometry (they generally shouldn't exist on original - * geometry). - */ - void attributes_remove_anonymous(); - - /** Returns true when the attribute has been created. */ - bool attribute_try_create(const blender::bke::AttributeIDRef &attribute_id, - eAttrDomain domain, - eCustomDataType data_type, - const AttributeInit &initializer); - - /** - * Try to create the builtin attribute with the given name. No data type or domain has to be - * provided, because those are fixed for builtin attributes. - */ - bool attribute_try_create_builtin(const blender::StringRef attribute_name, - const AttributeInit &initializer); - - blender::Set attribute_ids() const; - /** - * \return False if the callback explicitly returned false at any point, otherwise true, - * meaning the callback made it all the way through. - */ - bool attribute_foreach(const AttributeForeachCallback callback) const; - virtual bool is_empty() const; - - /** - * Get a virtual array that refers to the data of an attribute, interpolated to the given domain - * and converted to the data type. Returns null when the attribute does not exist or cannot be - * interpolated or converted. - */ - blender::GVArray attribute_try_get_for_read(const blender::bke::AttributeIDRef &attribute_id, - eAttrDomain domain, - eCustomDataType data_type) const; - - /** - * Get a virtual array that refers to the data of an attribute, interpolated to the given domain. - * The data type is left unchanged. Returns null when the attribute does not exist or cannot be - * interpolated. - */ - blender::GVArray attribute_try_get_for_read(const blender::bke::AttributeIDRef &attribute_id, - eAttrDomain domain) const; - - /** - * Get a virtual array that refers to the data of an attribute converted to the given data type. - * The attribute's domain is left unchanged. Returns null when the attribute does not exist or - * cannot be converted. - */ - blender::bke::ReadAttributeLookup attribute_try_get_for_read( - const blender::bke::AttributeIDRef &attribute_id, eCustomDataType data_type) const; - - /** - * Get a virtual array that refers to the data of an attribute, interpolated to the given domain - * and converted to the data type. If that is not possible, the returned virtual array will - * contain a default value. This never returns null. - */ - blender::GVArray attribute_get_for_read(const blender::bke::AttributeIDRef &attribute_id, - eAttrDomain domain, - eCustomDataType data_type, - const void *default_value = nullptr) const; - /* Use instead of the method above when the type is known at compile time for type safety. */ - template - blender::VArray attribute_get_for_read(const blender::bke::AttributeIDRef &attribute_id, - const eAttrDomain domain, - const T &default_value) const - { - const blender::CPPType &cpp_type = blender::CPPType::get(); - const eCustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type); - return this->attribute_get_for_read(attribute_id, domain, type, &default_value) - .template typed(); - } - - /** - * Returns an "output attribute", which is essentially a mutable virtual array with some commonly - * used convince features. The returned output attribute might be empty if requested attribute - * cannot exist on the geometry. - * - * The included convenience features are: - * - Implicit type conversion when writing to builtin attributes. - * - If the attribute name exists already, but has a different type/domain, a temporary attribute - * is created that will overwrite the existing attribute in the end. - */ - blender::bke::OutputAttribute attribute_try_get_for_output( - const blender::bke::AttributeIDRef &attribute_id, - eAttrDomain domain, - eCustomDataType data_type, - const void *default_value = nullptr); - /* Use instead of the method above when the type is known at compile time for type safety. */ - template - blender::bke::OutputAttribute_Typed attribute_try_get_for_output( - const blender::bke::AttributeIDRef &attribute_id, - const eAttrDomain domain, - const T default_value) - { - const blender::CPPType &cpp_type = blender::CPPType::get(); - const eCustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type); - return this->attribute_try_get_for_output(attribute_id, domain, data_type, &default_value); - } - - /** - * Same as #attribute_try_get_for_output, but should be used when the original values in the - * attributes are not read, i.e. the attribute is used only for output. The can be faster because - * it can avoid interpolation and conversion of existing values. Since values are not read from - * this attribute, no default value is necessary. - */ - blender::bke::OutputAttribute attribute_try_get_for_output_only( - const blender::bke::AttributeIDRef &attribute_id, - eAttrDomain domain, - eCustomDataType data_type); - /* Use instead of the method above when the type is known at compile time for type safety. */ - template - blender::bke::OutputAttribute_Typed attribute_try_get_for_output_only( - const blender::bke::AttributeIDRef &attribute_id, const eAttrDomain domain) - { - const blender::CPPType &cpp_type = blender::CPPType::get(); - const eCustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type); - return this->attribute_try_get_for_output_only(attribute_id, domain, data_type); - } - - private: - virtual const blender::bke::ComponentAttributeProviders *get_attribute_providers() const; - - virtual blender::GVArray attribute_try_adapt_domain_impl(const blender::GVArray &varray, - eAttrDomain from_domain, - eAttrDomain to_domain) const; }; template @@ -381,7 +195,7 @@ struct GeometrySet { using AttributeForeachCallback = blender::FunctionRef; void attribute_foreach(blender::Span component_types, @@ -392,7 +206,7 @@ struct GeometrySet { blender::Span component_types, GeometryComponentType dst_component_type, bool include_instances, - blender::Map &r_attributes) const; + blender::Map &r_attributes) const; blender::Vector gather_component_types(bool include_instances, bool ignore_empty) const; @@ -565,8 +379,6 @@ class MeshComponent : public GeometryComponent { */ Mesh *get_for_write(); - int attribute_domain_num(eAttrDomain domain) const final; - bool is_empty() const final; bool owns_direct_data() const override; @@ -574,12 +386,8 @@ class MeshComponent : public GeometryComponent { static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_MESH; - private: - const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final; - - blender::GVArray attribute_try_adapt_domain_impl(const blender::GVArray &varray, - eAttrDomain from_domain, - eAttrDomain to_domain) const final; + std::optional attributes() const final; + std::optional attributes_for_write() final; }; /** @@ -628,17 +436,17 @@ class PointCloudComponent : public GeometryComponent { */ PointCloud *get_for_write(); - int attribute_domain_num(eAttrDomain domain) const final; - bool is_empty() const final; bool owns_direct_data() const override; void ensure_owns_direct_data() override; + std::optional attributes() const final; + std::optional attributes_for_write() final; + static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_POINT_CLOUD; private: - const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final; }; /** @@ -669,21 +477,15 @@ class CurveComponentLegacy : public GeometryComponent { const CurveEval *get_for_read() const; CurveEval *get_for_write(); - int attribute_domain_num(eAttrDomain domain) const final; - 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_CURVE; + std::optional attributes() const final; + std::optional attributes_for_write() final; - private: - const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final; - - blender::GVArray attribute_try_adapt_domain_impl(const blender::GVArray &varray, - eAttrDomain from_domain, - eAttrDomain to_domain) const final; + static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_CURVE; }; /** @@ -721,8 +523,6 @@ class CurveComponent : public GeometryComponent { const Curves *get_for_read() const; Curves *get_for_write(); - int attribute_domain_num(eAttrDomain domain) const final; - bool is_empty() const final; bool owns_direct_data() const override; @@ -734,14 +534,10 @@ class CurveComponent : public GeometryComponent { */ const Curve *get_curve_for_render() const; - static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_CURVE; + std::optional attributes() const final; + std::optional attributes_for_write() final; - private: - const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final; - - blender::GVArray attribute_try_adapt_domain_impl(const blender::GVArray &varray, - eAttrDomain from_domain, - eAttrDomain to_domain) const final; + static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_CURVE; }; /** @@ -966,10 +762,11 @@ class InstancesComponent : public GeometryComponent { blender::Span almost_unique_ids() const; - blender::bke::CustomDataAttributes &attributes(); - const blender::bke::CustomDataAttributes &attributes() const; + blender::bke::CustomDataAttributes &instance_attributes(); + const blender::bke::CustomDataAttributes &instance_attributes() const; - int attribute_domain_num(eAttrDomain domain) const final; + std::optional attributes() const final; + std::optional attributes_for_write() final; void foreach_referenced_geometry( blender::FunctionRef callback) const; @@ -982,7 +779,6 @@ class InstancesComponent : public GeometryComponent { static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_INSTANCES; private: - const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final; }; /** diff --git a/source/blender/blenkernel/BKE_mesh_sample.hh b/source/blender/blenkernel/BKE_mesh_sample.hh index cbbd0249f4f..356709d8942 100644 --- a/source/blender/blenkernel/BKE_mesh_sample.hh +++ b/source/blender/blenkernel/BKE_mesh_sample.hh @@ -13,6 +13,7 @@ #include "DNA_meshdata_types.h" #include "BKE_attribute.h" +#include "BKE_attribute.hh" struct Mesh; struct BVHTreeFromMesh; @@ -21,11 +22,6 @@ namespace blender { class RandomNumberGenerator; } -namespace blender::bke { -struct ReadAttributeLookup; -class OutputAttribute; -} // namespace blender::bke - namespace blender::bke::mesh_surface_sample { void sample_point_attribute(const Mesh &mesh, @@ -81,8 +77,8 @@ class MeshAttributeInterpolator { eAttributeMapMode mode, const GMutableSpan dst); - void sample_attribute(const ReadAttributeLookup &src_attribute, - OutputAttribute &dst_attribute, + void sample_attribute(const GAttributeReader &src_attribute, + GSpanAttributeWriter &dst_attribute, eAttributeMapMode mode); protected: diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh index 28f326a4ad4..767018ae0bb 100644 --- a/source/blender/blenkernel/BKE_spline.hh +++ b/source/blender/blenkernel/BKE_spline.hh @@ -15,7 +15,7 @@ #include "BLI_math_vec_types.hh" #include "BLI_vector.hh" -#include "BKE_attribute_access.hh" +#include "BKE_attribute.hh" #include "BKE_attribute_math.hh" struct Curve; @@ -646,6 +646,8 @@ struct CurveEval { void transform(const blender::float4x4 &matrix); bool bounds_min_max(blender::float3 &min, blender::float3 &max, bool use_evaluated) const; + blender::bke::MutableAttributeAccessor attributes_for_write(); + /** * Return the start indices for each of the curve spline's control points, if they were part * of a flattened array. This can be used to facilitate parallelism by avoiding the need to diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index b2307c0e129..d0f9a67f167 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -325,7 +325,7 @@ set(SRC BKE_asset_library.h BKE_asset_library.hh BKE_attribute.h - BKE_attribute_access.hh + BKE_attribute.hh BKE_attribute_math.hh BKE_autoexec.h BKE_blender.h diff --git a/source/blender/blenkernel/intern/attribute.cc b/source/blender/blenkernel/intern/attribute.cc index 7c09b4a4ce3..030e4941874 100644 --- a/source/blender/blenkernel/intern/attribute.cc +++ b/source/blender/blenkernel/intern/attribute.cc @@ -23,7 +23,7 @@ #include "BLI_string_utils.h" #include "BKE_attribute.h" -#include "BKE_attribute_access.hh" +#include "BKE_attribute.hh" #include "BKE_curves.h" #include "BKE_customdata.h" #include "BKE_editmesh.h" diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index ee9358eb97e..ac1ee19927c 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -2,7 +2,6 @@ #include -#include "BKE_attribute_access.hh" #include "BKE_attribute_math.hh" #include "BKE_customdata.h" #include "BKE_deform.h" @@ -26,8 +25,6 @@ #include "attribute_access_intern.hh" -static CLG_LogRef LOG = {"bke.attribute_access"}; - using blender::float3; using blender::GMutableSpan; using blender::GSpan; @@ -36,7 +33,6 @@ using blender::Set; using blender::StringRef; using blender::StringRefNull; using blender::bke::AttributeIDRef; -using blender::bke::OutputAttribute; namespace blender::bke { @@ -151,36 +147,6 @@ eAttrDomain attribute_domain_highest_priority(Span domains) return highest_priority_domain; } -GMutableSpan OutputAttribute::as_span() -{ - if (!optional_span_varray_) { - const bool materialize_old_values = !ignore_old_values_; - optional_span_varray_ = std::make_unique(varray_, materialize_old_values); - } - GMutableVArraySpan &span_varray = *optional_span_varray_; - return span_varray; -} - -void OutputAttribute::save() -{ - save_has_been_called_ = true; - if (optional_span_varray_) { - optional_span_varray_->save(); - } - if (save_) { - save_(*this); - } -} - -OutputAttribute::~OutputAttribute() -{ - if (!save_has_been_called_) { - if (varray_) { - std::cout << "Warning: Call `save()` to make sure that changes persist in all cases.\n"; - } - } -} - static AttributeIDRef attribute_id_from_custom_data_layer(const CustomDataLayer &layer) { if (layer.anonymous_id != nullptr) { @@ -292,9 +258,9 @@ static bool custom_data_layer_matches_attribute_id(const CustomDataLayer &layer, return layer.name == attribute_id.name(); } -GVArray BuiltinCustomDataLayerProvider::try_get_for_read(const GeometryComponent &component) const +GVArray BuiltinCustomDataLayerProvider::try_get_for_read(const void *owner) const { - const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); + const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner); if (custom_data == nullptr) { return {}; } @@ -310,21 +276,20 @@ GVArray BuiltinCustomDataLayerProvider::try_get_for_read(const GeometryComponent return {}; } - const int domain_num = component.attribute_domain_num(domain_); - return as_read_attribute_(data, domain_num); + const int element_num = custom_data_access_.get_element_num(owner); + return as_read_attribute_(data, element_num); } -WriteAttributeLookup BuiltinCustomDataLayerProvider::try_get_for_write( - GeometryComponent &component) const +GAttributeWriter BuiltinCustomDataLayerProvider::try_get_for_write(void *owner) const { if (writable_ != Writable) { return {}; } - CustomData *custom_data = custom_data_access_.get_custom_data(component); + CustomData *custom_data = custom_data_access_.get_custom_data(owner); if (custom_data == nullptr) { return {}; } - const int domain_num = component.attribute_domain_num(domain_); + const int element_num = custom_data_access_.get_element_num(owner); void *data; if (stored_as_named_attribute_) { @@ -340,44 +305,42 @@ WriteAttributeLookup BuiltinCustomDataLayerProvider::try_get_for_write( void *new_data; if (stored_as_named_attribute_) { new_data = CustomData_duplicate_referenced_layer_named( - custom_data, stored_type_, name_.c_str(), domain_num); + custom_data, stored_type_, name_.c_str(), element_num); } else { - new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, domain_num); + new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, element_num); } if (data != new_data) { if (custom_data_access_.update_custom_data_pointers) { - custom_data_access_.update_custom_data_pointers(component); + custom_data_access_.update_custom_data_pointers(owner); } data = new_data; } std::function tag_modified_fn; if (update_on_write_ != nullptr) { - tag_modified_fn = [component = &component, update = update_on_write_]() { - update(*component); - }; + tag_modified_fn = [owner, update = update_on_write_]() { update(owner); }; } - return {as_write_attribute_(data, domain_num), domain_, std::move(tag_modified_fn)}; + return {as_write_attribute_(data, element_num), domain_, std::move(tag_modified_fn)}; } -bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) const +bool BuiltinCustomDataLayerProvider::try_delete(void *owner) const { if (deletable_ != Deletable) { return false; } - CustomData *custom_data = custom_data_access_.get_custom_data(component); + CustomData *custom_data = custom_data_access_.get_custom_data(owner); if (custom_data == nullptr) { return {}; } - const int domain_num = component.attribute_domain_num(domain_); + const int element_num = custom_data_access_.get_element_num(owner); if (stored_as_named_attribute_) { - if (CustomData_free_layer_named(custom_data, name_.c_str(), domain_num)) { + if (CustomData_free_layer_named(custom_data, name_.c_str(), element_num)) { if (custom_data_access_.update_custom_data_pointers) { - custom_data_access_.update_custom_data_pointers(component); + custom_data_access_.update_custom_data_pointers(owner); } return true; } @@ -385,27 +348,27 @@ bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) co } const int layer_index = CustomData_get_layer_index(custom_data, stored_type_); - if (CustomData_free_layer(custom_data, stored_type_, domain_num, layer_index)) { + if (CustomData_free_layer(custom_data, stored_type_, element_num, layer_index)) { if (custom_data_access_.update_custom_data_pointers) { - custom_data_access_.update_custom_data_pointers(component); + custom_data_access_.update_custom_data_pointers(owner); } return true; } return false; } -bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component, +bool BuiltinCustomDataLayerProvider::try_create(void *owner, const AttributeInit &initializer) const { if (createable_ != Creatable) { return false; } - CustomData *custom_data = custom_data_access_.get_custom_data(component); + CustomData *custom_data = custom_data_access_.get_custom_data(owner); if (custom_data == nullptr) { return false; } - const int domain_num = component.attribute_domain_num(domain_); + const int element_num = custom_data_access_.get_element_num(owner); bool success; if (stored_as_named_attribute_) { if (CustomData_get_layer_named(custom_data, data_type_, name_.c_str())) { @@ -413,7 +376,7 @@ bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component, return false; } success = add_custom_data_layer_from_attribute_init( - name_, *custom_data, stored_type_, domain_num, initializer); + name_, *custom_data, stored_type_, element_num, initializer); } else { if (CustomData_get_layer(custom_data, stored_type_) != nullptr) { @@ -421,19 +384,19 @@ bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component, return false; } success = add_builtin_type_custom_data_layer_from_init( - *custom_data, stored_type_, domain_num, initializer); + *custom_data, stored_type_, element_num, initializer); } if (success) { if (custom_data_access_.update_custom_data_pointers) { - custom_data_access_.update_custom_data_pointers(component); + custom_data_access_.update_custom_data_pointers(owner); } } return success; } -bool BuiltinCustomDataLayerProvider::exists(const GeometryComponent &component) const +bool BuiltinCustomDataLayerProvider::exists(const void *owner) const { - const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); + const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner); if (custom_data == nullptr) { return false; } @@ -443,14 +406,14 @@ bool BuiltinCustomDataLayerProvider::exists(const GeometryComponent &component) return CustomData_get_layer(custom_data, stored_type_) != nullptr; } -ReadAttributeLookup CustomDataAttributeProvider::try_get_for_read( - const GeometryComponent &component, const AttributeIDRef &attribute_id) const +GAttributeReader CustomDataAttributeProvider::try_get_for_read( + const void *owner, const AttributeIDRef &attribute_id) const { - const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); + const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner); if (custom_data == nullptr) { return {}; } - const int domain_num = component.attribute_domain_num(domain_); + const int element_num = custom_data_access_.get_element_num(owner); for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { if (!custom_data_layer_matches_attribute_id(layer, attribute_id)) { continue; @@ -459,61 +422,62 @@ ReadAttributeLookup CustomDataAttributeProvider::try_get_for_read( if (type == nullptr) { continue; } - GSpan data{*type, layer.data, domain_num}; + GSpan data{*type, layer.data, element_num}; return {GVArray::ForSpan(data), domain_}; } return {}; } -WriteAttributeLookup CustomDataAttributeProvider::try_get_for_write( - GeometryComponent &component, const AttributeIDRef &attribute_id) const +GAttributeWriter CustomDataAttributeProvider::try_get_for_write( + void *owner, const AttributeIDRef &attribute_id) const { - CustomData *custom_data = custom_data_access_.get_custom_data(component); + CustomData *custom_data = custom_data_access_.get_custom_data(owner); if (custom_data == nullptr) { return {}; } - const int domain_num = component.attribute_domain_num(domain_); + const int element_num = custom_data_access_.get_element_num(owner); for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) { if (!custom_data_layer_matches_attribute_id(layer, attribute_id)) { continue; } if (attribute_id.is_named()) { - CustomData_duplicate_referenced_layer_named(custom_data, layer.type, layer.name, domain_num); + CustomData_duplicate_referenced_layer_named( + custom_data, layer.type, layer.name, element_num); } else { CustomData_duplicate_referenced_layer_anonymous( - custom_data, layer.type, &attribute_id.anonymous_id(), domain_num); + custom_data, layer.type, &attribute_id.anonymous_id(), element_num); } const CPPType *type = custom_data_type_to_cpp_type((eCustomDataType)layer.type); if (type == nullptr) { continue; } - GMutableSpan data{*type, layer.data, domain_num}; + GMutableSpan data{*type, layer.data, element_num}; return {GVMutableArray::ForSpan(data), domain_}; } return {}; } -bool CustomDataAttributeProvider::try_delete(GeometryComponent &component, - const AttributeIDRef &attribute_id) const +bool CustomDataAttributeProvider::try_delete(void *owner, const AttributeIDRef &attribute_id) const { - CustomData *custom_data = custom_data_access_.get_custom_data(component); + CustomData *custom_data = custom_data_access_.get_custom_data(owner); if (custom_data == nullptr) { return false; } - const int domain_num = component.attribute_domain_num(domain_); + const int element_num = custom_data_access_.get_element_num(owner); + ; for (const int i : IndexRange(custom_data->totlayer)) { const CustomDataLayer &layer = custom_data->layers[i]; if (this->type_is_supported((eCustomDataType)layer.type) && custom_data_layer_matches_attribute_id(layer, attribute_id)) { - CustomData_free_layer(custom_data, layer.type, domain_num, i); + CustomData_free_layer(custom_data, layer.type, element_num, i); return true; } } return false; } -bool CustomDataAttributeProvider::try_create(GeometryComponent &component, +bool CustomDataAttributeProvider::try_create(void *owner, const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type, @@ -525,7 +489,7 @@ bool CustomDataAttributeProvider::try_create(GeometryComponent &component, if (!this->type_is_supported(data_type)) { return false; } - CustomData *custom_data = custom_data_access_.get_custom_data(component); + CustomData *custom_data = custom_data_access_.get_custom_data(owner); if (custom_data == nullptr) { return false; } @@ -534,16 +498,16 @@ bool CustomDataAttributeProvider::try_create(GeometryComponent &component, return false; } } - const int domain_num = component.attribute_domain_num(domain_); + const int element_num = custom_data_access_.get_element_num(owner); add_custom_data_layer_from_attribute_init( - attribute_id, *custom_data, data_type, domain_num, initializer); + attribute_id, *custom_data, data_type, element_num, initializer); return true; } -bool CustomDataAttributeProvider::foreach_attribute(const GeometryComponent &component, +bool CustomDataAttributeProvider::foreach_attribute(const void *owner, const AttributeForeachCallback callback) const { - const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); + const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner); if (custom_data == nullptr) { return true; } @@ -560,17 +524,17 @@ bool CustomDataAttributeProvider::foreach_attribute(const GeometryComponent &com return true; } -ReadAttributeLookup NamedLegacyCustomDataProvider::try_get_for_read( - const GeometryComponent &component, const AttributeIDRef &attribute_id) const +GAttributeReader NamedLegacyCustomDataProvider::try_get_for_read( + const void *owner, const AttributeIDRef &attribute_id) const { - const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); + const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner); if (custom_data == nullptr) { return {}; } for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { if (layer.type == stored_type_) { if (custom_data_layer_matches_attribute_id(layer, attribute_id)) { - const int domain_num = component.attribute_domain_num(domain_); + const int domain_num = custom_data_access_.get_element_num(owner); return {as_read_attribute_(layer.data, domain_num), domain_}; } } @@ -578,36 +542,36 @@ ReadAttributeLookup NamedLegacyCustomDataProvider::try_get_for_read( return {}; } -WriteAttributeLookup NamedLegacyCustomDataProvider::try_get_for_write( - GeometryComponent &component, const AttributeIDRef &attribute_id) const +GAttributeWriter NamedLegacyCustomDataProvider::try_get_for_write( + void *owner, const AttributeIDRef &attribute_id) const { - CustomData *custom_data = custom_data_access_.get_custom_data(component); + CustomData *custom_data = custom_data_access_.get_custom_data(owner); if (custom_data == nullptr) { return {}; } for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) { if (layer.type == stored_type_) { if (custom_data_layer_matches_attribute_id(layer, attribute_id)) { - const int domain_num = component.attribute_domain_num(domain_); + const int element_num = custom_data_access_.get_element_num(owner); void *data_old = layer.data; void *data_new = CustomData_duplicate_referenced_layer_named( - custom_data, stored_type_, layer.name, domain_num); + custom_data, stored_type_, layer.name, element_num); if (data_old != data_new) { if (custom_data_access_.update_custom_data_pointers) { - custom_data_access_.update_custom_data_pointers(component); + custom_data_access_.update_custom_data_pointers(owner); } } - return {as_write_attribute_(layer.data, domain_num), domain_}; + return {as_write_attribute_(layer.data, element_num), domain_}; } } } return {}; } -bool NamedLegacyCustomDataProvider::try_delete(GeometryComponent &component, +bool NamedLegacyCustomDataProvider::try_delete(void *owner, const AttributeIDRef &attribute_id) const { - CustomData *custom_data = custom_data_access_.get_custom_data(component); + CustomData *custom_data = custom_data_access_.get_custom_data(owner); if (custom_data == nullptr) { return false; } @@ -615,10 +579,10 @@ bool NamedLegacyCustomDataProvider::try_delete(GeometryComponent &component, const CustomDataLayer &layer = custom_data->layers[i]; if (layer.type == stored_type_) { if (custom_data_layer_matches_attribute_id(layer, attribute_id)) { - const int domain_num = component.attribute_domain_num(domain_); - CustomData_free_layer(custom_data, stored_type_, domain_num, i); + const int element_num = custom_data_access_.get_element_num(owner); + CustomData_free_layer(custom_data, stored_type_, element_num, i); if (custom_data_access_.update_custom_data_pointers) { - custom_data_access_.update_custom_data_pointers(component); + custom_data_access_.update_custom_data_pointers(owner); } return true; } @@ -628,9 +592,9 @@ bool NamedLegacyCustomDataProvider::try_delete(GeometryComponent &component, } bool NamedLegacyCustomDataProvider::foreach_attribute( - const GeometryComponent &component, const AttributeForeachCallback callback) const + const void *owner, const AttributeForeachCallback callback) const { - const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); + const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner); if (custom_data == nullptr) { return true; } @@ -804,275 +768,10 @@ void CustomDataAttributes::reorder(Span new_order) CustomData_update_typemap(&data); } -} // namespace blender::bke - /* -------------------------------------------------------------------- */ /** \name Geometry Component * \{ */ -const blender::bke::ComponentAttributeProviders *GeometryComponent::get_attribute_providers() const -{ - return nullptr; -} - -bool GeometryComponent::attribute_domain_supported(const eAttrDomain domain) const -{ - using namespace blender::bke; - const ComponentAttributeProviders *providers = this->get_attribute_providers(); - if (providers == nullptr) { - return false; - } - return providers->supported_domains().contains(domain); -} - -int GeometryComponent::attribute_domain_num(const eAttrDomain UNUSED(domain)) const -{ - return 0; -} - -bool GeometryComponent::attribute_is_builtin(const blender::StringRef attribute_name) const -{ - using namespace blender::bke; - const ComponentAttributeProviders *providers = this->get_attribute_providers(); - if (providers == nullptr) { - return false; - } - return providers->builtin_attribute_providers().contains_as(attribute_name); -} - -bool GeometryComponent::attribute_is_builtin(const AttributeIDRef &attribute_id) const -{ - /* Anonymous attributes cannot be built-in. */ - return attribute_id.is_named() && this->attribute_is_builtin(attribute_id.name()); -} - -blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read( - const AttributeIDRef &attribute_id) const -{ - using namespace blender::bke; - const ComponentAttributeProviders *providers = this->get_attribute_providers(); - if (providers == nullptr) { - return {}; - } - if (attribute_id.is_named()) { - const BuiltinAttributeProvider *builtin_provider = - providers->builtin_attribute_providers().lookup_default_as(attribute_id.name(), nullptr); - if (builtin_provider != nullptr) { - return {builtin_provider->try_get_for_read(*this), builtin_provider->domain()}; - } - } - for (const DynamicAttributesProvider *dynamic_provider : - providers->dynamic_attribute_providers()) { - ReadAttributeLookup attribute = dynamic_provider->try_get_for_read(*this, attribute_id); - if (attribute) { - return attribute; - } - } - return {}; -} - -blender::GVArray GeometryComponent::attribute_try_adapt_domain_impl( - const blender::GVArray &varray, - const eAttrDomain from_domain, - const eAttrDomain to_domain) const -{ - if (from_domain == to_domain) { - return varray; - } - return {}; -} - -blender::bke::WriteAttributeLookup GeometryComponent::attribute_try_get_for_write( - const AttributeIDRef &attribute_id) -{ - using namespace blender::bke; - const ComponentAttributeProviders *providers = this->get_attribute_providers(); - if (providers == nullptr) { - return {}; - } - if (attribute_id.is_named()) { - const BuiltinAttributeProvider *builtin_provider = - providers->builtin_attribute_providers().lookup_default_as(attribute_id.name(), nullptr); - if (builtin_provider != nullptr) { - return builtin_provider->try_get_for_write(*this); - } - } - for (const DynamicAttributesProvider *dynamic_provider : - providers->dynamic_attribute_providers()) { - WriteAttributeLookup attribute = dynamic_provider->try_get_for_write(*this, attribute_id); - if (attribute) { - return attribute; - } - } - return {}; -} - -bool GeometryComponent::attribute_try_delete(const AttributeIDRef &attribute_id) -{ - using namespace blender::bke; - const ComponentAttributeProviders *providers = this->get_attribute_providers(); - if (providers == nullptr) { - return {}; - } - if (attribute_id.is_named()) { - const BuiltinAttributeProvider *builtin_provider = - providers->builtin_attribute_providers().lookup_default_as(attribute_id.name(), nullptr); - if (builtin_provider != nullptr) { - return builtin_provider->try_delete(*this); - } - } - bool success = false; - for (const DynamicAttributesProvider *dynamic_provider : - providers->dynamic_attribute_providers()) { - success = dynamic_provider->try_delete(*this, attribute_id) || success; - } - return success; -} - -void GeometryComponent::attributes_remove_anonymous() -{ - using namespace blender; - Vector anonymous_ids; - for (const AttributeIDRef &id : this->attribute_ids()) { - if (id.is_anonymous()) { - anonymous_ids.append(&id.anonymous_id()); - } - } - - while (!anonymous_ids.is_empty()) { - this->attribute_try_delete(anonymous_ids.pop_last()); - } -} - -bool GeometryComponent::attribute_try_create(const AttributeIDRef &attribute_id, - const eAttrDomain domain, - const eCustomDataType data_type, - const AttributeInit &initializer) -{ - using namespace blender::bke; - if (!attribute_id) { - return false; - } - const ComponentAttributeProviders *providers = this->get_attribute_providers(); - if (providers == nullptr) { - return false; - } - if (this->attribute_exists(attribute_id)) { - return false; - } - if (attribute_id.is_named()) { - const BuiltinAttributeProvider *builtin_provider = - providers->builtin_attribute_providers().lookup_default_as(attribute_id.name(), nullptr); - if (builtin_provider != nullptr) { - if (builtin_provider->domain() != domain) { - return false; - } - if (builtin_provider->data_type() != data_type) { - return false; - } - return builtin_provider->try_create(*this, initializer); - } - } - for (const DynamicAttributesProvider *dynamic_provider : - providers->dynamic_attribute_providers()) { - if (dynamic_provider->try_create(*this, attribute_id, domain, data_type, initializer)) { - return true; - } - } - return false; -} - -bool GeometryComponent::attribute_try_create_builtin(const blender::StringRef attribute_name, - const AttributeInit &initializer) -{ - using namespace blender::bke; - if (attribute_name.is_empty()) { - return false; - } - const ComponentAttributeProviders *providers = this->get_attribute_providers(); - if (providers == nullptr) { - return false; - } - const BuiltinAttributeProvider *builtin_provider = - providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr); - if (builtin_provider == nullptr) { - return false; - } - return builtin_provider->try_create(*this, initializer); -} - -Set GeometryComponent::attribute_ids() const -{ - Set attributes; - this->attribute_foreach( - [&](const AttributeIDRef &attribute_id, const AttributeMetaData &UNUSED(meta_data)) { - attributes.add(attribute_id); - return true; - }); - return attributes; -} - -bool GeometryComponent::attribute_foreach(const AttributeForeachCallback callback) const -{ - using namespace blender::bke; - const ComponentAttributeProviders *providers = this->get_attribute_providers(); - if (providers == nullptr) { - return true; - } - - /* Keep track handled attribute names to make sure that we do not return the same name twice. */ - Set handled_attribute_names; - - for (const BuiltinAttributeProvider *provider : - providers->builtin_attribute_providers().values()) { - if (provider->exists(*this)) { - AttributeMetaData meta_data{provider->domain(), provider->data_type()}; - if (!callback(provider->name(), meta_data)) { - return false; - } - handled_attribute_names.add_new(provider->name()); - } - } - for (const DynamicAttributesProvider *provider : providers->dynamic_attribute_providers()) { - const bool continue_loop = provider->foreach_attribute( - *this, [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { - if (attribute_id.is_anonymous() || handled_attribute_names.add(attribute_id.name())) { - return callback(attribute_id, meta_data); - } - return true; - }); - if (!continue_loop) { - return false; - } - } - - return true; -} - -bool GeometryComponent::attribute_exists(const AttributeIDRef &attribute_id) const -{ - blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_id); - if (attribute) { - return true; - } - return false; -} - -std::optional GeometryComponent::attribute_get_meta_data( - const AttributeIDRef &attribute_id) const -{ - std::optional result{std::nullopt}; - this->attribute_foreach( - [&](const AttributeIDRef ¤t_attribute_id, const AttributeMetaData &meta_data) { - if (attribute_id == current_attribute_id) { - result = meta_data; - return false; - } - return true; - }); - return result; -} - static blender::GVArray try_adapt_data_type(blender::GVArray varray, const blender::CPPType &to_type) { @@ -1081,294 +780,6 @@ static blender::GVArray try_adapt_data_type(blender::GVArray varray, return conversions.try_convert(std::move(varray), to_type); } -blender::GVArray GeometryComponent::attribute_try_get_for_read( - const AttributeIDRef &attribute_id, - const eAttrDomain domain, - const eCustomDataType data_type) const -{ - blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_id); - if (!attribute) { - return {}; - } - - blender::GVArray varray = std::move(attribute.varray); - if (!ELEM(domain, ATTR_DOMAIN_AUTO, attribute.domain)) { - varray = this->attribute_try_adapt_domain(std::move(varray), attribute.domain, domain); - if (!varray) { - return {}; - } - } - - const blender::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type); - BLI_assert(cpp_type != nullptr); - if (varray.type() != *cpp_type) { - varray = try_adapt_data_type(std::move(varray), *cpp_type); - if (!varray) { - return {}; - } - } - - return varray; -} - -blender::GVArray GeometryComponent::attribute_try_get_for_read(const AttributeIDRef &attribute_id, - const eAttrDomain domain) const -{ - if (!this->attribute_domain_supported(domain)) { - return {}; - } - - blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_id); - if (!attribute) { - return {}; - } - - if (attribute.domain != domain) { - return this->attribute_try_adapt_domain(std::move(attribute.varray), attribute.domain, domain); - } - - return std::move(attribute.varray); -} - -blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read( - const AttributeIDRef &attribute_id, const eCustomDataType data_type) const -{ - blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_id); - if (!attribute) { - return {}; - } - const blender::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type); - BLI_assert(type != nullptr); - if (attribute.varray.type() == *type) { - return attribute; - } - const blender::bke::DataTypeConversions &conversions = - blender::bke::get_implicit_type_conversions(); - return {conversions.try_convert(std::move(attribute.varray), *type), attribute.domain}; -} - -blender::GVArray GeometryComponent::attribute_get_for_read(const AttributeIDRef &attribute_id, - const eAttrDomain domain, - const eCustomDataType data_type, - const void *default_value) const -{ - blender::GVArray varray = this->attribute_try_get_for_read(attribute_id, domain, data_type); - if (varray) { - return varray; - } - const blender::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type); - if (default_value == nullptr) { - default_value = type->default_value(); - } - const int domain_num = this->attribute_domain_num(domain); - return blender::GVArray::ForSingle(*type, domain_num, default_value); -} - -class GVMutableAttribute_For_OutputAttribute : public blender::GVArrayImpl_For_GSpan { - public: - GeometryComponent *component; - std::string attribute_name; - blender::bke::WeakAnonymousAttributeID anonymous_attribute_id; - - GVMutableAttribute_For_OutputAttribute(GMutableSpan data, - GeometryComponent &component, - const AttributeIDRef &attribute_id) - : blender::GVArrayImpl_For_GSpan(data), component(&component) - { - if (attribute_id.is_named()) { - this->attribute_name = attribute_id.name(); - } - else { - const AnonymousAttributeID *anonymous_id = &attribute_id.anonymous_id(); - BKE_anonymous_attribute_id_increment_weak(anonymous_id); - this->anonymous_attribute_id = blender::bke::WeakAnonymousAttributeID{anonymous_id}; - } - } - - ~GVMutableAttribute_For_OutputAttribute() override - { - type_->destruct_n(data_, size_); - MEM_freeN(data_); - } -}; - -static void save_output_attribute(OutputAttribute &output_attribute) -{ - using namespace blender; - using namespace blender::fn; - using namespace blender::bke; - - GVMutableAttribute_For_OutputAttribute &varray = - dynamic_cast( - *output_attribute.varray().get_implementation()); - - GeometryComponent &component = *varray.component; - AttributeIDRef attribute_id; - if (!varray.attribute_name.empty()) { - attribute_id = varray.attribute_name; - } - else { - attribute_id = varray.anonymous_attribute_id.extract(); - } - const eAttrDomain domain = output_attribute.domain(); - const eCustomDataType data_type = output_attribute.custom_data_type(); - const CPPType &cpp_type = output_attribute.cpp_type(); - - component.attribute_try_delete(attribute_id); - if (!component.attribute_try_create(attribute_id, domain, data_type, AttributeInitDefault())) { - if (!varray.attribute_name.empty()) { - CLOG_WARN(&LOG, - "Could not create the '%s' attribute with type '%s'.", - varray.attribute_name.c_str(), - cpp_type.name().c_str()); - } - return; - } - WriteAttributeLookup write_attribute = component.attribute_try_get_for_write(attribute_id); - BUFFER_FOR_CPP_TYPE_VALUE(varray.type(), buffer); - for (const int i : IndexRange(varray.size())) { - varray.get(i, buffer); - write_attribute.varray.set_by_relocate(i, buffer); - } - if (write_attribute.tag_modified_fn) { - write_attribute.tag_modified_fn(); - } -} - -static std::function get_simple_output_attribute_save_method( - const blender::bke::WriteAttributeLookup &attribute) -{ - if (!attribute.tag_modified_fn) { - return {}; - } - return [tag_modified_fn = attribute.tag_modified_fn](OutputAttribute &UNUSED(attribute)) { - tag_modified_fn(); - }; -} - -static OutputAttribute create_output_attribute(GeometryComponent &component, - const AttributeIDRef &attribute_id, - const eAttrDomain domain, - const eCustomDataType data_type, - const bool ignore_old_values, - const void *default_value) -{ - using namespace blender; - using namespace blender::fn; - using namespace blender::bke; - - if (!attribute_id) { - return {}; - } - - const CPPType *cpp_type = custom_data_type_to_cpp_type(data_type); - BLI_assert(cpp_type != nullptr); - const DataTypeConversions &conversions = get_implicit_type_conversions(); - - if (component.attribute_is_builtin(attribute_id)) { - const StringRef attribute_name = attribute_id.name(); - WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_name); - if (!attribute) { - if (default_value) { - const int64_t domain_num = component.attribute_domain_num(domain); - component.attribute_try_create_builtin( - attribute_name, - AttributeInitVArray(GVArray::ForSingleRef(*cpp_type, domain_num, default_value))); - } - else { - component.attribute_try_create_builtin(attribute_name, AttributeInitDefault()); - } - attribute = component.attribute_try_get_for_write(attribute_name); - if (!attribute) { - /* Builtin attribute does not exist and can't be created. */ - return {}; - } - } - if (attribute.domain != domain) { - /* Builtin attribute is on different domain. */ - return {}; - } - GVMutableArray varray = std::move(attribute.varray); - if (varray.type() == *cpp_type) { - /* Builtin attribute matches exactly. */ - return OutputAttribute(std::move(varray), - domain, - get_simple_output_attribute_save_method(attribute), - ignore_old_values); - } - /* Builtin attribute is on the same domain but has a different data type. */ - varray = conversions.try_convert(std::move(varray), *cpp_type); - return OutputAttribute(std::move(varray), - domain, - get_simple_output_attribute_save_method(attribute), - ignore_old_values); - } - - const int domain_num = component.attribute_domain_num(domain); - - WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_id); - if (!attribute) { - if (default_value) { - component.attribute_try_create( - attribute_id, - domain, - data_type, - AttributeInitVArray(GVArray::ForSingleRef(*cpp_type, domain_num, default_value))); - } - else { - component.attribute_try_create(attribute_id, domain, data_type, AttributeInitDefault()); - } - - attribute = component.attribute_try_get_for_write(attribute_id); - if (!attribute) { - /* Can't create the attribute. */ - return {}; - } - } - if (attribute.domain == domain && attribute.varray.type() == *cpp_type) { - /* Existing generic attribute matches exactly. */ - - return OutputAttribute(std::move(attribute.varray), - domain, - get_simple_output_attribute_save_method(attribute), - ignore_old_values); - } - - /* Allocate a new array that lives next to the existing attribute. It will overwrite the existing - * attribute after processing is done. */ - void *data = MEM_mallocN_aligned(cpp_type->size() * domain_num, cpp_type->alignment(), __func__); - if (ignore_old_values) { - /* This does nothing for trivially constructible types, but is necessary for correctness. */ - cpp_type->default_construct_n(data, domain); - } - else { - /* Fill the temporary array with values from the existing attribute. */ - GVArray old_varray = component.attribute_get_for_read( - attribute_id, domain, data_type, default_value); - old_varray.materialize_to_uninitialized(IndexRange(domain_num), data); - } - GVMutableArray varray = GVMutableArray::For( - GMutableSpan{*cpp_type, data, domain_num}, component, attribute_id); - - return OutputAttribute(std::move(varray), domain, save_output_attribute, true); -} - -OutputAttribute GeometryComponent::attribute_try_get_for_output(const AttributeIDRef &attribute_id, - const eAttrDomain domain, - const eCustomDataType data_type, - const void *default_value) -{ - return create_output_attribute(*this, attribute_id, domain, data_type, false, default_value); -} - -OutputAttribute GeometryComponent::attribute_try_get_for_output_only( - const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type) -{ - return create_output_attribute(*this, attribute_id, domain, data_type, true, nullptr); -} - -namespace blender::bke { - GVArray GeometryFieldInput::get_varray_for_context(const fn::FieldContext &context, IndexMask mask, ResourceScope &UNUSED(scope)) const @@ -1387,7 +798,10 @@ GVArray AttributeFieldInput::get_varray_for_context(const GeometryComponent &com IndexMask UNUSED(mask)) const { const eCustomDataType data_type = cpp_type_to_custom_data_type(*type_); - return component.attribute_try_get_for_read(name_, domain, data_type); + if (auto attributes = component.attributes()) { + return attributes->lookup(name_, domain, data_type); + } + return {}; } std::string AttributeFieldInput::socket_inspection_name() const @@ -1427,10 +841,10 @@ GVArray IDAttributeFieldInput::get_varray_for_context(const GeometryComponent &c { const StringRef name = get_random_id_attribute_name(domain); - GVArray attribute = component.attribute_try_get_for_read(name, domain, CD_PROP_INT32); - if (attribute) { - BLI_assert(attribute.size() == component.attribute_domain_num(domain)); - return attribute; + if (auto attributes = component.attributes()) { + if (GVArray attribute = attributes->lookup(name, domain, CD_PROP_INT32)) { + return attribute; + } } /* Use the index as the fallback if no random ID attribute exists. */ @@ -1459,7 +873,7 @@ GVArray AnonymousAttributeFieldInput::get_varray_for_context(const GeometryCompo IndexMask UNUSED(mask)) const { const eCustomDataType data_type = cpp_type_to_custom_data_type(*type_); - return component.attribute_try_get_for_read(anonymous_id_.get(), domain, data_type); + return component.attributes()->lookup(anonymous_id_.get(), domain, data_type); } std::string AnonymousAttributeFieldInput::socket_inspection_name() const @@ -1483,6 +897,120 @@ bool AnonymousAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const return false; } +GVArray AttributeAccessor::lookup(const AttributeIDRef &attribute_id, + const std::optional domain, + const std::optional data_type) const +{ + GAttributeReader attribute = this->lookup(attribute_id); + if (!attribute) { + return {}; + } + GVArray varray = std::move(attribute.varray); + if (domain.has_value()) { + if (attribute.domain != domain) { + varray = this->adapt_domain(varray, attribute.domain, *domain); + if (!varray) { + return {}; + } + } + } + if (data_type.has_value()) { + const CPPType &type = *custom_data_type_to_cpp_type(*data_type); + if (varray.type() != type) { + varray = try_adapt_data_type(std::move(varray), type); + if (!varray) { + return {}; + } + } + } + return varray; +} + +GVArray AttributeAccessor::lookup_or_default(const AttributeIDRef &attribute_id, + const eAttrDomain domain, + const eCustomDataType data_type, + const void *default_value) const +{ + GVArray varray = this->lookup(attribute_id, domain, data_type); + if (varray) { + return varray; + } + const CPPType &type = *custom_data_type_to_cpp_type(data_type); + const int64_t domain_size = this->domain_size(domain); + if (default_value == nullptr) { + return GVArray::ForSingleRef(type, domain_size, type.default_value()); + } + return GVArray::ForSingle(type, domain_size, default_value); +} + +Set AttributeAccessor::all_ids() const +{ + Set ids; + this->for_all( + [&](const AttributeIDRef &attribute_id, const AttributeMetaData & /* meta_data */) { + ids.add(attribute_id); + return true; + }); + return ids; +} + +void MutableAttributeAccessor::remove_anonymous() +{ + Vector anonymous_ids; + for (const AttributeIDRef &id : this->all_ids()) { + if (id.is_anonymous()) { + anonymous_ids.append(&id.anonymous_id()); + } + } + + while (!anonymous_ids.is_empty()) { + this->remove(anonymous_ids.pop_last()); + } +} + +GAttributeWriter MutableAttributeAccessor::lookup_or_add_for_write( + const AttributeIDRef &attribute_id, + const eAttrDomain domain, + const eCustomDataType data_type, + const AttributeInit &initializer) +{ + std::optional meta_data = this->lookup_meta_data(attribute_id); + if (meta_data.has_value()) { + if (meta_data->domain == domain && meta_data->data_type == data_type) { + return this->lookup_for_write(attribute_id); + } + return {}; + } + if (this->add(attribute_id, domain, data_type, initializer)) { + return this->lookup_for_write(attribute_id); + } + return {}; +} + +GSpanAttributeWriter MutableAttributeAccessor::lookup_or_add_for_write_span( + const AttributeIDRef &attribute_id, + const eAttrDomain domain, + const eCustomDataType data_type, + const AttributeInit &initializer) +{ + GAttributeWriter attribute = this->lookup_or_add_for_write( + attribute_id, domain, data_type, initializer); + if (attribute) { + return GSpanAttributeWriter{std::move(attribute), true}; + } + return {}; +} + +GSpanAttributeWriter MutableAttributeAccessor::lookup_or_add_for_write_only_span( + const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type) +{ + GAttributeWriter attribute = this->lookup_or_add_for_write(attribute_id, domain, data_type); + if (attribute) { + return GSpanAttributeWriter{std::move(attribute), false}; + } + return {}; +} + } // namespace blender::bke /** \} */ diff --git a/source/blender/blenkernel/intern/attribute_access_intern.hh b/source/blender/blenkernel/intern/attribute_access_intern.hh index ac43754dd1a..17432fa2726 100644 --- a/source/blender/blenkernel/intern/attribute_access_intern.hh +++ b/source/blender/blenkernel/intern/attribute_access_intern.hh @@ -15,12 +15,14 @@ namespace blender::bke { * components in a generic way. */ struct CustomDataAccessInfo { - using CustomDataGetter = CustomData *(*)(GeometryComponent &component); - using ConstCustomDataGetter = const CustomData *(*)(const GeometryComponent &component); - using UpdateCustomDataPointers = void (*)(GeometryComponent &component); + using CustomDataGetter = CustomData *(*)(void *owner); + using ConstCustomDataGetter = const CustomData *(*)(const void *owner); + using GetElementNum = int (*)(const void *owner); + using UpdateCustomDataPointers = void (*)(void *owner); CustomDataGetter get_custom_data; ConstCustomDataGetter get_const_custom_data; + GetElementNum get_element_num; UpdateCustomDataPointers update_custom_data_pointers; }; @@ -69,12 +71,11 @@ class BuiltinAttributeProvider { { } - virtual GVArray try_get_for_read(const GeometryComponent &component) const = 0; - virtual WriteAttributeLookup try_get_for_write(GeometryComponent &component) const = 0; - virtual bool try_delete(GeometryComponent &component) const = 0; - virtual bool try_create(GeometryComponent &UNUSED(component), - const AttributeInit &UNUSED(initializer)) const = 0; - virtual bool exists(const GeometryComponent &component) const = 0; + virtual GVArray try_get_for_read(const void *owner) const = 0; + virtual GAttributeWriter try_get_for_write(void *owner) const = 0; + virtual bool try_delete(void *owner) const = 0; + virtual bool try_create(void *onwer, const AttributeInit &initializer) const = 0; + virtual bool exists(const void *owner) const = 0; StringRefNull name() const { @@ -98,23 +99,23 @@ class BuiltinAttributeProvider { */ class DynamicAttributesProvider { public: - virtual ReadAttributeLookup try_get_for_read(const GeometryComponent &component, - const AttributeIDRef &attribute_id) const = 0; - virtual WriteAttributeLookup try_get_for_write(GeometryComponent &component, - const AttributeIDRef &attribute_id) const = 0; - virtual bool try_delete(GeometryComponent &component, - const AttributeIDRef &attribute_id) const = 0; - virtual bool try_create(GeometryComponent &UNUSED(component), - const AttributeIDRef &UNUSED(attribute_id), - const eAttrDomain UNUSED(domain), - const eCustomDataType UNUSED(data_type), - const AttributeInit &UNUSED(initializer)) const + virtual GAttributeReader try_get_for_read(const void *owner, + const AttributeIDRef &attribute_id) const = 0; + virtual GAttributeWriter try_get_for_write(void *owner, + const AttributeIDRef &attribute_id) const = 0; + virtual bool try_delete(void *owner, const AttributeIDRef &attribute_id) const = 0; + virtual bool try_create(void *owner, + const AttributeIDRef &attribute_id, + const eAttrDomain domain, + const eCustomDataType data_type, + const AttributeInit &initializer) const { + UNUSED_VARS(owner, attribute_id, domain, data_type, initializer); /* Some providers should not create new attributes. */ return false; }; - virtual bool foreach_attribute(const GeometryComponent &component, + virtual bool foreach_attribute(const void *owner, const AttributeForeachCallback callback) const = 0; virtual void foreach_domain(const FunctionRef callback) const = 0; }; @@ -138,22 +139,20 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider { { } - ReadAttributeLookup try_get_for_read(const GeometryComponent &component, - const AttributeIDRef &attribute_id) const final; + GAttributeReader try_get_for_read(const void *owner, + const AttributeIDRef &attribute_id) const final; - WriteAttributeLookup try_get_for_write(GeometryComponent &component, - const AttributeIDRef &attribute_id) const final; + GAttributeWriter try_get_for_write(void *owner, const AttributeIDRef &attribute_id) const final; - bool try_delete(GeometryComponent &component, const AttributeIDRef &attribute_id) const final; + bool try_delete(void *owner, const AttributeIDRef &attribute_id) const final; - bool try_create(GeometryComponent &component, + bool try_create(void *owner, const AttributeIDRef &attribute_id, eAttrDomain domain, const eCustomDataType data_type, const AttributeInit &initializer) const final; - bool foreach_attribute(const GeometryComponent &component, - const AttributeForeachCallback callback) const final; + bool foreach_attribute(const void *owner, const AttributeForeachCallback callback) const final; void foreach_domain(const FunctionRef callback) const final { @@ -197,13 +196,11 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider { { } - ReadAttributeLookup try_get_for_read(const GeometryComponent &component, - const AttributeIDRef &attribute_id) const final; - WriteAttributeLookup try_get_for_write(GeometryComponent &component, - const AttributeIDRef &attribute_id) const final; - bool try_delete(GeometryComponent &component, const AttributeIDRef &attribute_id) const final; - bool foreach_attribute(const GeometryComponent &component, - const AttributeForeachCallback callback) const final; + GAttributeReader try_get_for_read(const void *owner, + const AttributeIDRef &attribute_id) const final; + GAttributeWriter try_get_for_write(void *owner, const AttributeIDRef &attribute_id) const final; + bool try_delete(void *owner, const AttributeIDRef &attribute_id) const final; + bool foreach_attribute(const void *owner, const AttributeForeachCallback callback) const final; void foreach_domain(const FunctionRef callback) const final; }; @@ -226,10 +223,10 @@ template GVMutableArray make_array_write_attribute(void *data, const * if the stored type is the same as the attribute type. */ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { - using AsReadAttribute = GVArray (*)(const void *data, int domain_num); - using AsWriteAttribute = GVMutableArray (*)(void *data, int domain_num); - using UpdateOnRead = void (*)(const GeometryComponent &component); - using UpdateOnWrite = void (*)(GeometryComponent &component); + using AsReadAttribute = GVArray (*)(const void *data, int element_num); + using AsWriteAttribute = GVMutableArray (*)(void *data, int element_num); + using UpdateOnRead = void (*)(const void *owner); + using UpdateOnWrite = void (*)(void *owner); const eCustomDataType stored_type_; const CustomDataAccessInfo custom_data_access_; const AsReadAttribute as_read_attribute_; @@ -260,11 +257,11 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { { } - GVArray try_get_for_read(const GeometryComponent &component) const final; - WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final; - bool try_delete(GeometryComponent &component) const final; - bool try_create(GeometryComponent &component, const AttributeInit &initializer) const final; - bool exists(const GeometryComponent &component) const final; + GVArray try_get_for_read(const void *owner) const final; + GAttributeWriter try_get_for_write(void *owner) const final; + bool try_delete(void *owner) const final; + bool try_create(void *owner, const AttributeInit &initializer) const final; + bool exists(const void *owner) const final; }; /** @@ -321,4 +318,183 @@ class ComponentAttributeProviders { } }; +namespace attribute_accessor_functions { + +template +inline bool is_builtin(const void *UNUSED(owner), const AttributeIDRef &attribute_id) +{ + if (!attribute_id.is_named()) { + return false; + } + const StringRef name = attribute_id.name(); + return providers.builtin_attribute_providers().contains_as(name); +} + +template +inline GAttributeReader lookup(const void *owner, const AttributeIDRef &attribute_id) +{ + if (attribute_id.is_named()) { + const StringRef name = attribute_id.name(); + if (const BuiltinAttributeProvider *provider = + providers.builtin_attribute_providers().lookup_default_as(name, nullptr)) { + return {provider->try_get_for_read(owner), provider->domain()}; + } + } + for (const DynamicAttributesProvider *provider : providers.dynamic_attribute_providers()) { + GAttributeReader attribute = provider->try_get_for_read(owner, attribute_id); + if (attribute) { + return attribute; + } + } + return {}; +} + +template +inline bool for_all(const void *owner, + FunctionRef fn) +{ + Set handled_attribute_ids; + for (const BuiltinAttributeProvider *provider : + providers.builtin_attribute_providers().values()) { + if (provider->exists(owner)) { + AttributeMetaData meta_data{provider->domain(), provider->data_type()}; + if (!fn(provider->name(), meta_data)) { + return false; + } + handled_attribute_ids.add_new(provider->name()); + } + } + for (const DynamicAttributesProvider *provider : providers.dynamic_attribute_providers()) { + const bool continue_loop = provider->foreach_attribute( + owner, [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { + if (handled_attribute_ids.add(attribute_id)) { + return fn(attribute_id, meta_data); + } + return true; + }); + if (!continue_loop) { + return false; + } + } + return true; +} + +template +inline bool contains(const void *owner, const blender::bke::AttributeIDRef &attribute_id) +{ + bool found = false; + for_all( + owner, + [&](const AttributeIDRef &other_attribute_id, const AttributeMetaData & /* meta_data */) { + if (attribute_id == other_attribute_id) { + found = true; + return false; + } + return true; + }); + return found; +} + +template +inline std::optional lookup_meta_data(const void *owner, + const AttributeIDRef &attribute_id) +{ + std::optional meta_data; + for_all( + owner, + [&](const AttributeIDRef &other_attribute_id, const AttributeMetaData &other_meta_data) { + if (attribute_id == other_attribute_id) { + meta_data = other_meta_data; + return false; + } + return true; + }); + return meta_data; +} + +template +inline GAttributeWriter lookup_for_write(void *owner, const AttributeIDRef &attribute_id) +{ + if (attribute_id.is_named()) { + const StringRef name = attribute_id.name(); + if (const BuiltinAttributeProvider *provider = + providers.builtin_attribute_providers().lookup_default_as(name, nullptr)) { + return provider->try_get_for_write(owner); + } + } + for (const DynamicAttributesProvider *provider : providers.dynamic_attribute_providers()) { + GAttributeWriter attribute = provider->try_get_for_write(owner, attribute_id); + if (attribute) { + return attribute; + } + } + return {}; +} + +template +inline bool remove(void *owner, const AttributeIDRef &attribute_id) +{ + if (attribute_id.is_named()) { + const StringRef name = attribute_id.name(); + if (const BuiltinAttributeProvider *provider = + providers.builtin_attribute_providers().lookup_default_as(name, nullptr)) { + return provider->try_delete(owner); + } + } + bool success = false; + for (const DynamicAttributesProvider *provider : providers.dynamic_attribute_providers()) { + success = provider->try_delete(owner, attribute_id) || success; + } + return success; +} + +template +inline bool add(void *owner, + const AttributeIDRef &attribute_id, + eAttrDomain domain, + eCustomDataType data_type, + const AttributeInit &initializer) +{ + if (contains(owner, attribute_id)) { + return false; + } + if (attribute_id.is_named()) { + const StringRef name = attribute_id.name(); + if (const BuiltinAttributeProvider *provider = + providers.builtin_attribute_providers().lookup_default_as(name, nullptr)) { + if (provider->domain() != domain) { + return false; + } + if (provider->data_type() != data_type) { + return false; + } + return provider->try_create(owner, initializer); + } + } + for (const DynamicAttributesProvider *provider : providers.dynamic_attribute_providers()) { + if (provider->try_create(owner, attribute_id, domain, data_type, initializer)) { + return true; + } + } + return false; +} + +template +inline AttributeAccessorFunctions accessor_functions_for_providers() +{ + return AttributeAccessorFunctions{contains, + lookup_meta_data, + nullptr, + nullptr, + is_builtin, + lookup, + nullptr, + for_all, + lookup_for_write, + remove, + add}; +} + +} // namespace attribute_accessor_functions + } // namespace blender::bke diff --git a/source/blender/blenkernel/intern/curve_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc index c01a184c6f9..424fa311dc7 100644 --- a/source/blender/blenkernel/intern/curve_eval.cc +++ b/source/blender/blenkernel/intern/curve_eval.cc @@ -31,9 +31,7 @@ using blender::VArray; using blender::VArraySpan; using blender::Vector; using blender::bke::AttributeIDRef; -using blender::bke::OutputAttribute; -using blender::bke::OutputAttribute_Typed; -using blender::bke::ReadAttributeLookup; +using blender::bke::AttributeMetaData; blender::Span CurveEval::splines() const { @@ -345,32 +343,31 @@ std::unique_ptr curve_eval_from_dna_curve(const Curve &dna_curve) return curve_eval_from_dna_curve(dna_curve, *BKE_curve_nurbs_get_for_read(&dna_curve)); } -static void copy_attributes_between_components(const GeometryComponent &src_component, - GeometryComponent &dst_component, - Span skip) +static void copy_attributes_between_components( + const blender::bke::AttributeAccessor &src_attributes, + blender::bke::MutableAttributeAccessor &dst_attributes, + Span skip) { - src_component.attribute_foreach( - [&](const AttributeIDRef &id, const AttributeMetaData meta_data) { - if (id.is_named() && skip.contains(id.name())) { - return true; - } + src_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) { + if (id.is_named() && skip.contains(id.name())) { + return true; + } - GVArray src_attribute = src_component.attribute_try_get_for_read( - id, meta_data.domain, meta_data.data_type); - if (!src_attribute) { - return true; - } - GVArraySpan src_attribute_data{src_attribute}; + GVArray src_attribute = src_attributes.lookup(id, meta_data.domain, meta_data.data_type); + if (!src_attribute) { + return true; + } + GVArraySpan src_attribute_data{src_attribute}; - OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( - id, meta_data.domain, meta_data.data_type); - if (!dst_attribute) { - return true; - } - dst_attribute.varray().set_all(src_attribute_data.data()); - dst_attribute.save(); - return true; - }); + blender::bke::GAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write( + id, meta_data.domain, meta_data.data_type); + if (!dst_attribute) { + return true; + } + dst_attribute.varray.set_all(src_attribute_data.data()); + dst_attribute.finish(); + return true; + }); } std::unique_ptr curves_to_curve_eval(const Curves &curves_id) @@ -379,21 +376,22 @@ std::unique_ptr curves_to_curve_eval(const Curves &curves_id) src_component.replace(&const_cast(curves_id), GeometryOwnershipType::ReadOnly); const blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap( curves_id.geometry); + const blender::bke::AttributeAccessor src_attributes = curves.attributes(); VArray resolution = curves.resolution(); VArray normal_mode = curves.normal_mode(); VArraySpan nurbs_weights{ - src_component.attribute_get_for_read("nurbs_weight", ATTR_DOMAIN_POINT, 0.0f)}; + src_attributes.lookup_or_default("nurbs_weight", ATTR_DOMAIN_POINT, 0.0f)}; VArraySpan nurbs_orders{ - src_component.attribute_get_for_read("nurbs_order", ATTR_DOMAIN_CURVE, 4)}; + src_attributes.lookup_or_default("nurbs_order", ATTR_DOMAIN_CURVE, 4)}; VArraySpan nurbs_knots_modes{ - src_component.attribute_get_for_read("knots_mode", ATTR_DOMAIN_CURVE, 0)}; + src_attributes.lookup_or_default("knots_mode", ATTR_DOMAIN_CURVE, 0)}; VArraySpan handle_types_right{ - src_component.attribute_get_for_read("handle_type_right", ATTR_DOMAIN_POINT, 0)}; + src_attributes.lookup_or_default("handle_type_right", ATTR_DOMAIN_POINT, 0)}; VArraySpan handle_types_left{ - src_component.attribute_get_for_read("handle_type_left", ATTR_DOMAIN_POINT, 0)}; + src_attributes.lookup_or_default("handle_type_left", ATTR_DOMAIN_POINT, 0)}; /* Create splines with the correct size and type. */ VArray curve_types = curves.curve_types(); @@ -446,9 +444,10 @@ std::unique_ptr curves_to_curve_eval(const Curves &curves_id) CurveComponentLegacy dst_component; dst_component.replace(curve_eval.get(), GeometryOwnershipType::Editable); + blender::bke::MutableAttributeAccessor dst_attributes = *dst_component.attributes_for_write(); - copy_attributes_between_components(src_component, - dst_component, + copy_attributes_between_components(src_attributes, + dst_attributes, {"curve_type", "resolution", "normal_mode", @@ -467,37 +466,38 @@ Curves *curve_eval_to_curves(const CurveEval &curve_eval) curve_eval.splines().size()); CurveComponent dst_component; dst_component.replace(curves_id, GeometryOwnershipType::Editable); + blender::bke::MutableAttributeAccessor dst_attributes = *dst_component.attributes_for_write(); blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap(curves_id->geometry); curves.offsets_for_write().copy_from(curve_eval.control_point_offsets()); MutableSpan curve_types = curves.curve_types_for_write(); - OutputAttribute_Typed normal_mode = - dst_component.attribute_try_get_for_output_only("normal_mode", ATTR_DOMAIN_CURVE); - OutputAttribute_Typed nurbs_weight; - OutputAttribute_Typed nurbs_order; - OutputAttribute_Typed nurbs_knots_mode; + blender::bke::SpanAttributeWriter normal_mode = + dst_attributes.lookup_or_add_for_write_only_span("normal_mode", ATTR_DOMAIN_CURVE); + blender::bke::SpanAttributeWriter nurbs_weight; + blender::bke::SpanAttributeWriter nurbs_order; + blender::bke::SpanAttributeWriter nurbs_knots_mode; if (curve_eval.has_spline_with_type(CURVE_TYPE_NURBS)) { - nurbs_weight = dst_component.attribute_try_get_for_output_only("nurbs_weight", - ATTR_DOMAIN_POINT); - nurbs_order = dst_component.attribute_try_get_for_output_only("nurbs_order", - ATTR_DOMAIN_CURVE); - nurbs_knots_mode = dst_component.attribute_try_get_for_output_only("knots_mode", - ATTR_DOMAIN_CURVE); + nurbs_weight = dst_attributes.lookup_or_add_for_write_only_span("nurbs_weight", + ATTR_DOMAIN_POINT); + nurbs_order = dst_attributes.lookup_or_add_for_write_only_span("nurbs_order", + ATTR_DOMAIN_CURVE); + nurbs_knots_mode = dst_attributes.lookup_or_add_for_write_only_span("knots_mode", + ATTR_DOMAIN_CURVE); } - OutputAttribute_Typed handle_type_right; - OutputAttribute_Typed handle_type_left; + blender::bke::SpanAttributeWriter handle_type_right; + blender::bke::SpanAttributeWriter handle_type_left; if (curve_eval.has_spline_with_type(CURVE_TYPE_BEZIER)) { - handle_type_right = dst_component.attribute_try_get_for_output_only( + handle_type_right = dst_attributes.lookup_or_add_for_write_only_span( "handle_type_right", ATTR_DOMAIN_POINT); - handle_type_left = dst_component.attribute_try_get_for_output_only("handle_type_left", - ATTR_DOMAIN_POINT); + handle_type_left = dst_attributes.lookup_or_add_for_write_only_span("handle_type_left", + ATTR_DOMAIN_POINT); } for (const int curve_index : curve_eval.splines().index_range()) { const Spline &spline = *curve_eval.splines()[curve_index]; curve_types[curve_index] = curve_eval.splines()[curve_index]->type(); - normal_mode.as_span()[curve_index] = curve_eval.splines()[curve_index]->normal_mode; + normal_mode.span[curve_index] = curve_eval.splines()[curve_index]->normal_mode; const IndexRange points = curves.points_for_curve(curve_index); switch (spline.type()) { @@ -505,15 +505,15 @@ Curves *curve_eval_to_curves(const CurveEval &curve_eval) break; case CURVE_TYPE_BEZIER: { const BezierSpline &src = static_cast(spline); - handle_type_right.as_span().slice(points).copy_from(src.handle_types_right()); - handle_type_left.as_span().slice(points).copy_from(src.handle_types_left()); + handle_type_right.span.slice(points).copy_from(src.handle_types_right()); + handle_type_left.span.slice(points).copy_from(src.handle_types_left()); break; } case CURVE_TYPE_NURBS: { const NURBSpline &src = static_cast(spline); - nurbs_knots_mode.as_span()[curve_index] = static_cast(src.knots_mode); - nurbs_order.as_span()[curve_index] = src.order(); - nurbs_weight.as_span().slice(points).copy_from(src.weights()); + nurbs_knots_mode.span[curve_index] = static_cast(src.knots_mode); + nurbs_order.span[curve_index] = src.order(); + nurbs_weight.span.slice(points).copy_from(src.weights()); break; } case CURVE_TYPE_CATMULL_ROM: { @@ -525,17 +525,18 @@ Curves *curve_eval_to_curves(const CurveEval &curve_eval) curves.update_curve_types(); - normal_mode.save(); - nurbs_weight.save(); - nurbs_order.save(); - nurbs_knots_mode.save(); - handle_type_right.save(); - handle_type_left.save(); + normal_mode.finish(); + nurbs_weight.finish(); + nurbs_order.finish(); + nurbs_knots_mode.finish(); + handle_type_right.finish(); + handle_type_left.finish(); CurveComponentLegacy src_component; src_component.replace(&const_cast(curve_eval), GeometryOwnershipType::ReadOnly); + const blender::bke::AttributeAccessor src_attributes = *src_component.attributes(); - copy_attributes_between_components(src_component, dst_component, {}); + copy_attributes_between_components(src_attributes, dst_attributes, {}); return curves_id; } diff --git a/source/blender/blenkernel/intern/curve_legacy_convert.cc b/source/blender/blenkernel/intern/curve_legacy_convert.cc index 299a0fbb44c..ff5bbc32afe 100644 --- a/source/blender/blenkernel/intern/curve_legacy_convert.cc +++ b/source/blender/blenkernel/intern/curve_legacy_convert.cc @@ -83,8 +83,7 @@ Curves *curve_legacy_to_curves(const Curve &curve_legacy, const ListBase &nurbs_ Curves *curves_id = curves_new_nomain(0, src_curves.size()); CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry); - CurveComponent component; - component.replace(curves_id, GeometryOwnershipType::Editable); + MutableAttributeAccessor curves_attributes = curves.attributes_for_write(); MutableSpan types = curves.curve_types_for_write(); MutableSpan cyclic = curves.cyclic_for_write(); @@ -110,9 +109,9 @@ Curves *curve_legacy_to_curves(const Curve &curve_legacy, const ListBase &nurbs_ } MutableSpan positions = curves.positions_for_write(); - OutputAttribute_Typed radius_attribute = - component.attribute_try_get_for_output_only("radius", ATTR_DOMAIN_POINT); - MutableSpan radii = radius_attribute.as_span(); + SpanAttributeWriter radius_attribute = + curves_attributes.lookup_or_add_for_write_only_span("radius", ATTR_DOMAIN_POINT); + MutableSpan radii = radius_attribute.span; MutableSpan tilts = curves.tilt_for_write(); auto create_poly = [&](IndexMask selection) { @@ -203,7 +202,7 @@ Curves *curve_legacy_to_curves(const Curve &curve_legacy, const ListBase &nurbs_ curves.normal_mode_for_write().fill(normal_mode_from_legacy(curve_legacy.twist_mode)); - radius_attribute.save(); + radius_attribute.finish(); return curves_id; } diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc index baf56c0c350..7f051b683b4 100644 --- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc +++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc @@ -8,7 +8,6 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "BKE_attribute_access.hh" #include "BKE_attribute_math.hh" #include "BKE_curves.hh" #include "BKE_geometry_set.hh" @@ -315,15 +314,15 @@ static ResultOffsets calculate_result_offsets(const CurvesInfo &info, const bool return result; } -static eAttrDomain get_attribute_domain_for_mesh(const MeshComponent &mesh, +static eAttrDomain get_attribute_domain_for_mesh(const AttributeAccessor &mesh_attributes, const AttributeIDRef &attribute_id) { /* Only use a different domain if it is builtin and must only exist on one domain. */ - if (!mesh.attribute_is_builtin(attribute_id)) { + if (!mesh_attributes.is_builtin(attribute_id)) { return ATTR_DOMAIN_POINT; } - std::optional meta_data = mesh.attribute_get_meta_data(attribute_id); + std::optional meta_data = mesh_attributes.lookup_meta_data(attribute_id); if (!meta_data) { return ATTR_DOMAIN_POINT; } @@ -331,16 +330,17 @@ static eAttrDomain get_attribute_domain_for_mesh(const MeshComponent &mesh, return meta_data->domain; } -static bool should_add_attribute_to_mesh(const CurveComponent &curve_component, - const MeshComponent &mesh_component, +static bool should_add_attribute_to_mesh(const AttributeAccessor &curve_attributes, + const AttributeAccessor &mesh_attributes, const AttributeIDRef &id) { + /* The position attribute has special non-generic evaluation. */ if (id.is_named() && id.name() == "position") { return false; } /* Don't propagate built-in curves attributes that are not built-in on meshes. */ - if (curve_component.attribute_is_builtin(id) && !mesh_component.attribute_is_builtin(id)) { + if (curve_attributes.is_builtin(id) && !mesh_attributes.is_builtin(id)) { return false; } if (!id.should_be_kept()) { @@ -667,20 +667,13 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main, Vector eval_buffer; - Curves main_id = {{nullptr}}; - main_id.geometry = reinterpret_cast(main); - CurveComponent main_component; - main_component.replace(&main_id, GeometryOwnershipType::Editable); - - Curves profile_id = {{nullptr}}; - profile_id.geometry = reinterpret_cast(profile); - CurveComponent profile_component; - profile_component.replace(&profile_id, GeometryOwnershipType::Editable); + const AttributeAccessor main_attributes = main.attributes(); + const AttributeAccessor profile_attributes = profile.attributes(); Span radii = {}; - if (main_component.attribute_exists("radius")) { + if (main_attributes.contains("radius")) { radii = evaluated_attribute_if_necessary( - main_component.attribute_get_for_read("radius", ATTR_DOMAIN_POINT, 1.0f), + main_attributes.lookup_or_default("radius", ATTR_DOMAIN_POINT, 1.0f), main, main.curve_type_counts(), eval_buffer) @@ -716,24 +709,23 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main, }); } - Set main_attributes; + Set main_attributes_set; - MeshComponent mesh_component; - mesh_component.replace(mesh, GeometryOwnershipType::Editable); + MutableAttributeAccessor mesh_attributes = bke::mesh_attributes_for_write(*mesh); - main_component.attribute_foreach([&](const AttributeIDRef &id, - const AttributeMetaData meta_data) { - if (!should_add_attribute_to_mesh(main_component, mesh_component, id)) { + main_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) { + if (!should_add_attribute_to_mesh(main_attributes, mesh_attributes, id)) { return true; } - main_attributes.add_new(id); + main_attributes_set.add_new(id); const eAttrDomain src_domain = meta_data.domain; const eCustomDataType type = meta_data.data_type; - GVArray src = main_component.attribute_try_get_for_read(id, src_domain, type); + GVArray src = main_attributes.lookup(id, src_domain, type); - const eAttrDomain dst_domain = get_attribute_domain_for_mesh(mesh_component, id); - OutputAttribute dst = mesh_component.attribute_try_get_for_output_only(id, dst_domain, type); + const eAttrDomain dst_domain = get_attribute_domain_for_mesh(mesh_attributes, id); + GSpanAttributeWriter dst = mesh_attributes.lookup_or_add_for_write_only_span( + id, dst_domain, type); if (!dst) { return true; } @@ -744,31 +736,31 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main, offsets, dst_domain, evaluated_attribute_if_necessary(src, main, main.curve_type_counts(), eval_buffer), - dst.as_span()); + dst.span); } else if (src_domain == ATTR_DOMAIN_CURVE) { copy_curve_domain_attribute_to_mesh( - offsets, offsets.main_indices, dst_domain, src, dst.as_span()); + offsets, offsets.main_indices, dst_domain, src, dst.span); } - dst.save(); + dst.finish(); return true; }); - profile_component.attribute_foreach([&](const AttributeIDRef &id, - const AttributeMetaData meta_data) { + profile_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) { if (main_attributes.contains(id)) { return true; } - if (!should_add_attribute_to_mesh(profile_component, mesh_component, id)) { + if (!should_add_attribute_to_mesh(profile_attributes, mesh_attributes, id)) { return true; } const eAttrDomain src_domain = meta_data.domain; const eCustomDataType type = meta_data.data_type; - GVArray src = profile_component.attribute_try_get_for_read(id, src_domain, type); + GVArray src = profile_attributes.lookup(id, src_domain, type); - const eAttrDomain dst_domain = get_attribute_domain_for_mesh(mesh_component, id); - OutputAttribute dst = mesh_component.attribute_try_get_for_output_only(id, dst_domain, type); + const eAttrDomain dst_domain = get_attribute_domain_for_mesh(mesh_attributes, id); + GSpanAttributeWriter dst = mesh_attributes.lookup_or_add_for_write_only_span( + id, dst_domain, type); if (!dst) { return true; } @@ -779,14 +771,14 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main, offsets, dst_domain, evaluated_attribute_if_necessary(src, profile, profile.curve_type_counts(), eval_buffer), - dst.as_span()); + dst.span); } else if (src_domain == ATTR_DOMAIN_CURVE) { copy_curve_domain_attribute_to_mesh( - offsets, offsets.profile_indices, dst_domain, src, dst.as_span()); + offsets, offsets.profile_indices, dst_domain, src, dst.span); } - dst.save(); + dst.finish(); return true; }); diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc index 5725c6043b2..0d899ec7b06 100644 --- a/source/blender/blenkernel/intern/geometry_component_curve.cc +++ b/source/blender/blenkernel/intern/geometry_component_curve.cc @@ -5,7 +5,6 @@ #include "DNA_ID_enums.h" #include "DNA_curve_types.h" -#include "BKE_attribute_access.hh" #include "BKE_attribute_math.hh" #include "BKE_curve.h" #include "BKE_geometry_set.hh" @@ -114,24 +113,6 @@ void CurveComponentLegacy::ensure_owns_direct_data() /** \name Attribute Access Helper Functions * \{ */ -int CurveComponentLegacy::attribute_domain_num(const eAttrDomain domain) const -{ - if (curve_ == nullptr) { - return 0; - } - if (domain == ATTR_DOMAIN_POINT) { - int total = 0; - for (const SplinePtr &spline : curve_->splines()) { - total += spline->size(); - } - return total; - } - if (domain == ATTR_DOMAIN_CURVE) { - return curve_->splines().size(); - } - return 0; -} - namespace blender::bke { namespace { @@ -308,9 +289,10 @@ static GVArray adapt_curve_domain_spline_to_point(const CurveEval &curve, GVArra } // namespace blender::bke -GVArray CurveComponentLegacy::attribute_try_adapt_domain_impl(const GVArray &varray, - const eAttrDomain from_domain, - const eAttrDomain to_domain) const +static GVArray adapt_curve_attribute_domain(const CurveEval &curve, + const GVArray &varray, + const eAttrDomain from_domain, + const eAttrDomain to_domain) { if (!varray) { return {}; @@ -323,30 +305,15 @@ GVArray CurveComponentLegacy::attribute_try_adapt_domain_impl(const GVArray &var } if (from_domain == ATTR_DOMAIN_POINT && to_domain == ATTR_DOMAIN_CURVE) { - return blender::bke::adapt_curve_domain_point_to_spline(*curve_, std::move(varray)); + return blender::bke::adapt_curve_domain_point_to_spline(curve, std::move(varray)); } if (from_domain == ATTR_DOMAIN_CURVE && to_domain == ATTR_DOMAIN_POINT) { - return blender::bke::adapt_curve_domain_spline_to_point(*curve_, std::move(varray)); + return blender::bke::adapt_curve_domain_spline_to_point(curve, std::move(varray)); } return {}; } -static CurveEval *get_curve_from_component_for_write(GeometryComponent &component) -{ - BLI_assert(component.type() == GEO_COMPONENT_TYPE_CURVE); - CurveComponentLegacy &curve_component = static_cast(component); - return curve_component.get_for_write(); -} - -static const CurveEval *get_curve_from_component_for_read(const GeometryComponent &component) -{ - BLI_assert(component.type() == GEO_COMPONENT_TYPE_CURVE); - const CurveComponentLegacy &curve_component = static_cast( - component); - return curve_component.get_for_read(); -} - /** \} */ namespace blender::bke { @@ -380,41 +347,41 @@ class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider { { } - GVArray try_get_for_read(const GeometryComponent &component) const final + GVArray try_get_for_read(const void *owner) const final { - const CurveEval *curve = get_curve_from_component_for_read(component); + const CurveEval *curve = static_cast(owner); if (curve == nullptr) { return {}; } return as_read_attribute_(*curve); } - WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final + GAttributeWriter try_get_for_write(void *owner) const final { if (writable_ != Writable) { return {}; } - CurveEval *curve = get_curve_from_component_for_write(component); + CurveEval *curve = static_cast(owner); if (curve == nullptr) { return {}; } return {as_write_attribute_(*curve), domain_}; } - bool try_delete(GeometryComponent &UNUSED(component)) const final + bool try_delete(void *UNUSED(owner)) const final { return false; } - bool try_create(GeometryComponent &UNUSED(component), - const AttributeInit &UNUSED(initializer)) const final + bool try_create(void *UNUSED(owner), const AttributeInit &UNUSED(initializer)) const final { return false; } - bool exists(const GeometryComponent &component) const final + bool exists(const void *owner) const final { - return component.attribute_domain_num(ATTR_DOMAIN_CURVE) != 0; + const CurveEval *curve = static_cast(owner); + return !curve->splines().is_empty(); } }; @@ -600,12 +567,11 @@ static GVArray varray_from_initializer(const AttributeInit &initializer, return {}; } -static bool create_point_attribute(GeometryComponent &component, +static bool create_point_attribute(CurveEval *curve, const AttributeIDRef &attribute_id, const AttributeInit &initializer, const eCustomDataType data_type) { - CurveEval *curve = get_curve_from_component_for_write(component); if (curve == nullptr || curve->splines().size() == 0) { return false; } @@ -638,7 +604,7 @@ static bool create_point_attribute(GeometryComponent &component, return true; } - WriteAttributeLookup write_attribute = component.attribute_try_get_for_write(attribute_id); + GAttributeWriter write_attribute = curve->attributes_for_write().lookup_for_write(attribute_id); /* We just created the attribute, it should exist. */ BLI_assert(write_attribute); @@ -647,6 +613,7 @@ static bool create_point_attribute(GeometryComponent &component, * this theoretically unnecessary materialize step could be removed. */ GVArraySpan source_VArraySpan{source_varray}; write_attribute.varray.set_all(source_VArraySpan.data()); + write_attribute.finish(); if (initializer.type == AttributeInit::Type::MoveArray) { MEM_freeN(static_cast(initializer).data); @@ -655,10 +622,8 @@ static bool create_point_attribute(GeometryComponent &component, return true; } -static bool remove_point_attribute(GeometryComponent &component, - const AttributeIDRef &attribute_id) +static bool remove_point_attribute(CurveEval *curve, const AttributeIDRef &attribute_id) { - CurveEval *curve = get_curve_from_component_for_write(component); if (curve == nullptr) { return false; } @@ -934,14 +899,14 @@ template class BuiltinPointAttributeProvider : public BuiltinAttribu { } - GVArray try_get_for_read(const GeometryComponent &component) const override + GVArray try_get_for_read(const void *owner) const override { - const CurveEval *curve = get_curve_from_component_for_read(component); + const CurveEval *curve = static_cast(owner); if (curve == nullptr) { return {}; } - if (!this->exists(component)) { + if (!this->exists(owner)) { return {}; } @@ -962,14 +927,14 @@ template class BuiltinPointAttributeProvider : public BuiltinAttribu return point_data_varray(spans, offsets); } - WriteAttributeLookup try_get_for_write(GeometryComponent &component) const override + GAttributeWriter try_get_for_write(void *owner) const override { - CurveEval *curve = get_curve_from_component_for_write(component); + CurveEval *curve = static_cast(owner); if (curve == nullptr) { return {}; } - if (!this->exists(component)) { + if (!this->exists(owner)) { return {}; } @@ -998,25 +963,27 @@ template class BuiltinPointAttributeProvider : public BuiltinAttribu return {point_data_varray_mutable(spans, offsets), domain_, tag_modified_fn}; } - bool try_delete(GeometryComponent &component) const final + bool try_delete(void *owner) const final { if (deletable_ == DeletableEnum::NonDeletable) { return false; } - return remove_point_attribute(component, name_); + CurveEval *curve = static_cast(owner); + return remove_point_attribute(curve, name_); } - bool try_create(GeometryComponent &component, const AttributeInit &initializer) const final + bool try_create(void *owner, const AttributeInit &initializer) const final { if (createable_ == CreatableEnum::NonCreatable) { return false; } - return create_point_attribute(component, name_, initializer, CD_PROP_INT32); + CurveEval *curve = static_cast(owner); + return create_point_attribute(curve, name_, initializer, CD_PROP_INT32); } - bool exists(const GeometryComponent &component) const final + bool exists(const void *owner) const final { - const CurveEval *curve = get_curve_from_component_for_read(component); + const CurveEval *curve = static_cast(owner); if (curve == nullptr) { return false; } @@ -1067,9 +1034,9 @@ class PositionAttributeProvider final : public BuiltinPointAttributeProvider(owner); if (curve == nullptr) { return {}; } @@ -1077,7 +1044,7 @@ class PositionAttributeProvider final : public BuiltinPointAttributeProviderhas_spline_with_type(CURVE_TYPE_BEZIER)) { - return BuiltinPointAttributeProvider::try_get_for_write(component); + return BuiltinPointAttributeProvider::try_get_for_write(owner); } auto tag_modified_fn = [curve]() { @@ -1110,9 +1077,9 @@ class BezierHandleAttributeProvider : public BuiltinAttributeProvider { { } - GVArray try_get_for_read(const GeometryComponent &component) const override + GVArray try_get_for_read(const void *owner) const override { - const CurveEval *curve = get_curve_from_component_for_read(component); + const CurveEval *curve = static_cast(owner); if (curve == nullptr) { return {}; } @@ -1128,9 +1095,9 @@ class BezierHandleAttributeProvider : public BuiltinAttributeProvider { const_cast(curve)->splines(), std::move(offsets), is_right_); } - WriteAttributeLookup try_get_for_write(GeometryComponent &component) const override + GAttributeWriter try_get_for_write(void *owner) const override { - CurveEval *curve = get_curve_from_component_for_write(component); + CurveEval *curve = static_cast(owner); if (curve == nullptr) { return {}; } @@ -1148,26 +1115,27 @@ class BezierHandleAttributeProvider : public BuiltinAttributeProvider { tag_modified_fn}; } - bool try_delete(GeometryComponent &UNUSED(component)) const final + bool try_delete(void *UNUSED(owner)) const final { return false; } - bool try_create(GeometryComponent &UNUSED(component), - const AttributeInit &UNUSED(initializer)) const final + bool try_create(void *UNUSED(owner), const AttributeInit &UNUSED(initializer)) const final { return false; } - bool exists(const GeometryComponent &component) const final + bool exists(const void *owner) const final { - const CurveEval *curve = get_curve_from_component_for_read(component); + const CurveEval *curve = static_cast(owner); if (curve == nullptr) { return false; } - return curve->has_spline_with_type(CURVE_TYPE_BEZIER) && - component.attribute_domain_num(ATTR_DOMAIN_POINT) != 0; + CurveComponentLegacy component; + component.replace(const_cast(curve), GeometryOwnershipType::ReadOnly); + + return curve->has_spline_with_type(CURVE_TYPE_BEZIER) && !curve->splines().is_empty(); } }; @@ -1190,10 +1158,10 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider { CD_MASK_PROP_INT8; public: - ReadAttributeLookup try_get_for_read(const GeometryComponent &component, - const AttributeIDRef &attribute_id) const final + GAttributeReader try_get_for_read(const void *owner, + const AttributeIDRef &attribute_id) const final { - const CurveEval *curve = get_curve_from_component_for_read(component); + const CurveEval *curve = static_cast(owner); if (curve == nullptr || curve->splines().size() == 0) { return {}; } @@ -1228,7 +1196,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider { return {GVArray::ForSpan(spans.first()), ATTR_DOMAIN_POINT}; } - ReadAttributeLookup attribute = {}; + GAttributeReader attribute = {}; Array offsets = curve->control_point_offsets(); attribute_math::convert_to_static_type(spans[0].type(), [&](auto dummy) { using T = decltype(dummy); @@ -1246,10 +1214,9 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider { } /* This function is almost the same as #try_get_for_read, but without const. */ - WriteAttributeLookup try_get_for_write(GeometryComponent &component, - const AttributeIDRef &attribute_id) const final + GAttributeWriter try_get_for_write(void *owner, const AttributeIDRef &attribute_id) const final { - CurveEval *curve = get_curve_from_component_for_write(component); + CurveEval *curve = static_cast(owner); if (curve == nullptr || curve->splines().size() == 0) { return {}; } @@ -1284,7 +1251,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider { return {GVMutableArray::ForSpan(spans.first()), ATTR_DOMAIN_POINT}; } - WriteAttributeLookup attribute = {}; + GAttributeWriter attribute = {}; Array offsets = curve->control_point_offsets(); attribute_math::convert_to_static_type(spans[0].type(), [&](auto dummy) { using T = decltype(dummy); @@ -1298,12 +1265,13 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider { return attribute; } - bool try_delete(GeometryComponent &component, const AttributeIDRef &attribute_id) const final + bool try_delete(void *owner, const AttributeIDRef &attribute_id) const final { - return remove_point_attribute(component, attribute_id); + CurveEval *curve = static_cast(owner); + return remove_point_attribute(curve, attribute_id); } - bool try_create(GeometryComponent &component, + bool try_create(void *owner, const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type, @@ -1313,13 +1281,13 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider { if (domain != ATTR_DOMAIN_POINT) { return false; } - return create_point_attribute(component, attribute_id, initializer, data_type); + CurveEval *curve = static_cast(owner); + return create_point_attribute(curve, attribute_id, initializer, data_type); } - bool foreach_attribute(const GeometryComponent &component, - const AttributeForeachCallback callback) const final + bool foreach_attribute(const void *owner, const AttributeForeachCallback callback) const final { - const CurveEval *curve = get_curve_from_component_for_read(component); + const CurveEval *curve = static_cast(owner); if (curve == nullptr || curve->splines().size() == 0) { return false; } @@ -1371,14 +1339,18 @@ static ComponentAttributeProviders create_attribute_providers_for_curve() make_cyclic_write_attribute); static CustomDataAccessInfo spline_custom_data_access = { - [](GeometryComponent &component) -> CustomData * { - CurveEval *curve = get_curve_from_component_for_write(component); + [](void *owner) -> CustomData * { + CurveEval *curve = static_cast(owner); return curve ? &curve->attributes.data : nullptr; }, - [](const GeometryComponent &component) -> const CustomData * { - const CurveEval *curve = get_curve_from_component_for_read(component); + [](const void *owner) -> const CustomData * { + const CurveEval *curve = static_cast(owner); return curve ? &curve->attributes.data : nullptr; }, + [](const void *owner) -> int { + const CurveEval *curve = static_cast(owner); + return curve->splines().size(); + }, nullptr}; static CustomDataAttributeProvider spline_custom_data(ATTR_DOMAIN_CURVE, @@ -1430,12 +1402,62 @@ static ComponentAttributeProviders create_attribute_providers_for_curve() /** \} */ +static AttributeAccessorFunctions get_curve_accessor_functions() +{ + static const ComponentAttributeProviders providers = create_attribute_providers_for_curve(); + AttributeAccessorFunctions fn = + attribute_accessor_functions::accessor_functions_for_providers(); + fn.domain_size = [](const void *owner, const eAttrDomain domain) -> int { + if (owner == nullptr) { + return 0; + } + const CurveEval &curve_eval = *static_cast(owner); + switch (domain) { + case ATTR_DOMAIN_POINT: + return curve_eval.total_control_point_num(); + case ATTR_DOMAIN_CURVE: + return curve_eval.splines().size(); + default: + return 0; + } + }; + fn.domain_supported = [](const void *UNUSED(owner), const eAttrDomain domain) { + return ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); + }; + fn.adapt_domain = [](const void *owner, + const blender::GVArray &varray, + const eAttrDomain from_domain, + const eAttrDomain to_domain) -> GVArray { + if (owner == nullptr) { + return {}; + } + const CurveEval &curve_eval = *static_cast(owner); + return adapt_curve_attribute_domain(curve_eval, varray, from_domain, to_domain); + }; + return fn; +} + +static const AttributeAccessorFunctions &get_curve_accessor_functions_ref() +{ + static const AttributeAccessorFunctions fn = get_curve_accessor_functions(); + return fn; +} + } // namespace blender::bke -const blender::bke::ComponentAttributeProviders *CurveComponentLegacy::get_attribute_providers() - const +std::optional CurveComponentLegacy::attributes() const +{ + return blender::bke::AttributeAccessor(curve_, blender::bke::get_curve_accessor_functions_ref()); +} + +std::optional CurveComponentLegacy::attributes_for_write() +{ + return blender::bke::MutableAttributeAccessor(curve_, + blender::bke::get_curve_accessor_functions_ref()); +} + +blender::bke::MutableAttributeAccessor CurveEval::attributes_for_write() { - static blender::bke::ComponentAttributeProviders providers = - blender::bke::create_attribute_providers_for_curve(); - return &providers; + return blender::bke::MutableAttributeAccessor(this, + blender::bke::get_curve_accessor_functions_ref()); } diff --git a/source/blender/blenkernel/intern/geometry_component_curves.cc b/source/blender/blenkernel/intern/geometry_component_curves.cc index af058534f68..34c17bedc2c 100644 --- a/source/blender/blenkernel/intern/geometry_component_curves.cc +++ b/source/blender/blenkernel/intern/geometry_component_curves.cc @@ -5,7 +5,6 @@ #include "DNA_ID_enums.h" #include "DNA_curve_types.h" -#include "BKE_attribute_access.hh" #include "BKE_attribute_math.hh" #include "BKE_curve.h" #include "BKE_curves.hh" @@ -218,7 +217,7 @@ VArray curve_normals_varray(const CurveComponent &component, const eAttr const VArray types = curves.curve_types(); if (curves.is_single_type(CURVE_TYPE_POLY)) { - return component.attribute_try_adapt_domain( + return component.attributes()->adapt_domain( VArray::ForSpan(curves.evaluated_normals()), ATTR_DOMAIN_POINT, domain); } @@ -229,7 +228,7 @@ VArray curve_normals_varray(const CurveComponent &component, const eAttr } if (domain == ATTR_DOMAIN_CURVE) { - return component.attribute_try_adapt_domain( + return component.attributes()->adapt_domain( VArray::ForContainer(std::move(normals)), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); } @@ -264,7 +263,7 @@ static VArray construct_curve_length_gvarray(const CurveComponent &compon } if (domain == ATTR_DOMAIN_POINT) { - return component.attribute_try_adapt_domain( + return component.attributes()->adapt_domain( std::move(lengths), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT); } @@ -307,75 +306,29 @@ bool CurveLengthFieldInput::is_equal_to(const fn::FieldNode &other) const /** \name Attribute Access Helper Functions * \{ */ -int CurveComponent::attribute_domain_num(const eAttrDomain domain) const +static void tag_component_topology_changed(void *owner) { - if (curves_ == nullptr) { - return 0; - } - const blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap( - curves_->geometry); - if (domain == ATTR_DOMAIN_POINT) { - return curves.points_num(); - } - if (domain == ATTR_DOMAIN_CURVE) { - return curves.curves_num(); - } - return 0; -} - -GVArray CurveComponent::attribute_try_adapt_domain_impl(const GVArray &varray, - const eAttrDomain from_domain, - const eAttrDomain to_domain) const -{ - return blender::bke::CurvesGeometry::wrap(curves_->geometry) - .adapt_domain(varray, from_domain, to_domain); -} - -static Curves *get_curves_from_component_for_write(GeometryComponent &component) -{ - BLI_assert(component.type() == GEO_COMPONENT_TYPE_CURVE); - CurveComponent &curve_component = static_cast(component); - return curve_component.get_for_write(); -} - -static const Curves *get_curves_from_component_for_read(const GeometryComponent &component) -{ - BLI_assert(component.type() == GEO_COMPONENT_TYPE_CURVE); - const CurveComponent &curve_component = static_cast(component); - return curve_component.get_for_read(); + blender::bke::CurvesGeometry &curves = *static_cast(owner); + curves.tag_topology_changed(); } -static void tag_component_topology_changed(GeometryComponent &component) +static void tag_component_curve_types_changed(void *owner) { - Curves *curves = get_curves_from_component_for_write(component); - if (curves) { - blender::bke::CurvesGeometry::wrap(curves->geometry).tag_topology_changed(); - } + blender::bke::CurvesGeometry &curves = *static_cast(owner); + curves.update_curve_types(); + curves.tag_topology_changed(); } -static void tag_component_curve_types_changed(GeometryComponent &component) +static void tag_component_positions_changed(void *owner) { - Curves *curves = get_curves_from_component_for_write(component); - if (curves) { - blender::bke::CurvesGeometry::wrap(curves->geometry).update_curve_types(); - blender::bke::CurvesGeometry::wrap(curves->geometry).tag_topology_changed(); - } + blender::bke::CurvesGeometry &curves = *static_cast(owner); + curves.tag_positions_changed(); } -static void tag_component_positions_changed(GeometryComponent &component) +static void tag_component_normals_changed(void *owner) { - Curves *curves = get_curves_from_component_for_write(component); - if (curves) { - blender::bke::CurvesGeometry::wrap(curves->geometry).tag_positions_changed(); - } -} - -static void tag_component_normals_changed(GeometryComponent &component) -{ - Curves *curves = get_curves_from_component_for_write(component); - if (curves) { - blender::bke::CurvesGeometry::wrap(curves->geometry).tag_normals_changed(); - } + blender::bke::CurvesGeometry &curves = *static_cast(owner); + curves.tag_normals_changed(); } /** \} */ @@ -393,34 +346,38 @@ namespace blender::bke { static ComponentAttributeProviders create_attribute_providers_for_curve() { static CustomDataAccessInfo curve_access = { - [](GeometryComponent &component) -> CustomData * { - Curves *curves = get_curves_from_component_for_write(component); - return curves ? &curves->geometry.curve_data : nullptr; + [](void *owner) -> CustomData * { + CurvesGeometry &curves = *static_cast(owner); + return &curves.curve_data; }, - [](const GeometryComponent &component) -> const CustomData * { - const Curves *curves = get_curves_from_component_for_read(component); - return curves ? &curves->geometry.curve_data : nullptr; + [](const void *owner) -> const CustomData * { + const CurvesGeometry &curves = *static_cast(owner); + return &curves.curve_data; }, - [](GeometryComponent &component) { - Curves *curves = get_curves_from_component_for_write(component); - if (curves) { - blender::bke::CurvesGeometry::wrap(curves->geometry).update_customdata_pointers(); - } + [](const void *owner) -> int { + const CurvesGeometry &curves = *static_cast(owner); + return curves.curves_num(); + }, + [](void *owner) { + CurvesGeometry &curves = *static_cast(owner); + curves.update_customdata_pointers(); }}; static CustomDataAccessInfo point_access = { - [](GeometryComponent &component) -> CustomData * { - Curves *curves = get_curves_from_component_for_write(component); - return curves ? &curves->geometry.point_data : nullptr; + [](void *owner) -> CustomData * { + CurvesGeometry &curves = *static_cast(owner); + return &curves.point_data; }, - [](const GeometryComponent &component) -> const CustomData * { - const Curves *curves = get_curves_from_component_for_read(component); - return curves ? &curves->geometry.point_data : nullptr; + [](const void *owner) -> const CustomData * { + const CurvesGeometry &curves = *static_cast(owner); + return &curves.point_data; }, - [](GeometryComponent &component) { - Curves *curves = get_curves_from_component_for_write(component); - if (curves) { - blender::bke::CurvesGeometry::wrap(curves->geometry).update_customdata_pointers(); - } + [](const void *owner) -> int { + const CurvesGeometry &curves = *static_cast(owner); + return curves.points_num(); + }, + [](void *owner) { + CurvesGeometry &curves = *static_cast(owner); + curves.update_customdata_pointers(); }}; static BuiltinCustomDataLayerProvider position("position", @@ -626,11 +583,67 @@ static ComponentAttributeProviders create_attribute_providers_for_curve() /** \} */ +static AttributeAccessorFunctions get_curves_accessor_functions() +{ + static const ComponentAttributeProviders providers = create_attribute_providers_for_curve(); + AttributeAccessorFunctions fn = + attribute_accessor_functions::accessor_functions_for_providers(); + fn.domain_size = [](const void *owner, const eAttrDomain domain) { + if (owner == nullptr) { + return 0; + } + const CurvesGeometry &curves = *static_cast(owner); + switch (domain) { + case ATTR_DOMAIN_POINT: + return curves.points_num(); + case ATTR_DOMAIN_CURVE: + return curves.curves_num(); + default: + return 0; + } + }; + fn.domain_supported = [](const void *UNUSED(owner), const eAttrDomain domain) { + return ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); + }; + fn.adapt_domain = [](const void *owner, + const blender::GVArray &varray, + const eAttrDomain from_domain, + const eAttrDomain to_domain) -> GVArray { + if (owner == nullptr) { + return {}; + } + const CurvesGeometry &curves = *static_cast(owner); + return curves.adapt_domain(varray, from_domain, to_domain); + }; + return fn; +} + +static const AttributeAccessorFunctions &get_curves_accessor_functions_ref() +{ + static const AttributeAccessorFunctions fn = get_curves_accessor_functions(); + return fn; +} + +AttributeAccessor CurvesGeometry::attributes() const +{ + return AttributeAccessor(this, get_curves_accessor_functions_ref()); +} + +MutableAttributeAccessor CurvesGeometry::attributes_for_write() +{ + return MutableAttributeAccessor(this, get_curves_accessor_functions_ref()); +} + } // namespace blender::bke -const blender::bke::ComponentAttributeProviders *CurveComponent::get_attribute_providers() const +std::optional CurveComponent::attributes() const +{ + return blender::bke::AttributeAccessor(curves_ ? &curves_->geometry : nullptr, + blender::bke::get_curves_accessor_functions_ref()); +} + +std::optional CurveComponent::attributes_for_write() { - static blender::bke::ComponentAttributeProviders providers = - blender::bke::create_attribute_providers_for_curve(); - return &providers; + return blender::bke::MutableAttributeAccessor(curves_ ? &curves_->geometry : nullptr, + blender::bke::get_curves_accessor_functions_ref()); } diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc index 653be03b991..c16311945ba 100644 --- a/source/blender/blenkernel/intern/geometry_component_instances.cc +++ b/source/blender/blenkernel/intern/geometry_component_instances.cc @@ -13,7 +13,6 @@ #include "DNA_collection_types.h" -#include "BKE_attribute_access.hh" #include "BKE_attribute_math.hh" #include "BKE_geometry_set.hh" #include "BKE_geometry_set_instances.hh" @@ -157,7 +156,7 @@ void InstancesComponent::remove_instances(const IndexMask mask) dst_attributes.reallocate(mask.size()); src_attributes.foreach_attribute( - [&](const bke::AttributeIDRef &id, const AttributeMetaData &meta_data) { + [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData &meta_data) { if (!id.should_be_kept()) { return true; } @@ -366,20 +365,12 @@ blender::Span InstancesComponent::almost_unique_ids() const return almost_unique_ids_; } -int InstancesComponent::attribute_domain_num(const eAttrDomain domain) const -{ - if (domain != ATTR_DOMAIN_INSTANCE) { - return 0; - } - return this->instances_num(); -} - -blender::bke::CustomDataAttributes &InstancesComponent::attributes() +blender::bke::CustomDataAttributes &InstancesComponent::instance_attributes() { return this->attributes_; } -const blender::bke::CustomDataAttributes &InstancesComponent::attributes() const +const blender::bke::CustomDataAttributes &InstancesComponent::instance_attributes() const { return this->attributes_; } @@ -404,17 +395,17 @@ class InstancePositionAttributeProvider final : public BuiltinAttributeProvider { } - GVArray try_get_for_read(const GeometryComponent &component) const final + GVArray try_get_for_read(const void *owner) const final { - const InstancesComponent &instances_component = static_cast( - component); + const InstancesComponent &instances_component = *static_cast( + owner); Span transforms = instances_component.instance_transforms(); return VArray::ForDerivedSpan(transforms); } - WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final + GAttributeWriter try_get_for_write(void *owner) const final { - InstancesComponent &instances_component = static_cast(component); + InstancesComponent &instances_component = *static_cast(owner); MutableSpan transforms = instances_component.instance_transforms(); return {VMutableArray::ForDerivedSpan CustomData * { - InstancesComponent &inst = static_cast(component); - return &inst.attributes().data; + [](void *owner) -> CustomData * { + InstancesComponent &inst = *static_cast(owner); + return &inst.instance_attributes().data; + }, + [](const void *owner) -> const CustomData * { + const InstancesComponent &inst = *static_cast(owner); + return &inst.instance_attributes().data; }, - [](const GeometryComponent &component) -> const CustomData * { - const InstancesComponent &inst = static_cast(component); - return &inst.attributes().data; + [](const void *owner) -> int { + const InstancesComponent &inst = *static_cast(owner); + return inst.instances_num(); }, nullptr}; @@ -476,14 +470,57 @@ static ComponentAttributeProviders create_attribute_providers_for_instances() return ComponentAttributeProviders({&position, &id}, {&instance_custom_data}); } + +static AttributeAccessorFunctions get_instances_accessor_functions() +{ + static const ComponentAttributeProviders providers = create_attribute_providers_for_instances(); + AttributeAccessorFunctions fn = + attribute_accessor_functions::accessor_functions_for_providers(); + fn.domain_size = [](const void *owner, const eAttrDomain domain) { + if (owner == nullptr) { + return 0; + } + const InstancesComponent &instances = *static_cast(owner); + switch (domain) { + case ATTR_DOMAIN_INSTANCE: + return instances.instances_num(); + default: + return 0; + } + }; + fn.domain_supported = [](const void *UNUSED(owner), const eAttrDomain domain) { + return domain == ATTR_DOMAIN_INSTANCE; + }; + fn.adapt_domain = [](const void *UNUSED(owner), + const blender::GVArray &varray, + const eAttrDomain from_domain, + const eAttrDomain to_domain) { + if (from_domain == to_domain && from_domain == ATTR_DOMAIN_INSTANCE) { + return varray; + } + return blender::GVArray{}; + }; + return fn; +} + +static const AttributeAccessorFunctions &get_instances_accessor_functions_ref() +{ + static const AttributeAccessorFunctions fn = get_instances_accessor_functions(); + return fn; +} + } // namespace blender::bke -const blender::bke::ComponentAttributeProviders *InstancesComponent::get_attribute_providers() - const +std::optional InstancesComponent::attributes() const +{ + return blender::bke::AttributeAccessor(this, + blender::bke::get_instances_accessor_functions_ref()); +} + +std::optional InstancesComponent::attributes_for_write() { - static blender::bke::ComponentAttributeProviders providers = - blender::bke::create_attribute_providers_for_instances(); - return &providers; + return blender::bke::MutableAttributeAccessor( + this, blender::bke::get_instances_accessor_functions_ref()); } /** \} */ diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index 9e64acf218b..cb36b9b19f7 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -7,7 +7,6 @@ #include "DNA_meshdata_types.h" #include "DNA_object_types.h" -#include "BKE_attribute_access.hh" #include "BKE_attribute_math.hh" #include "BKE_deform.h" #include "BKE_geometry_fields.hh" @@ -151,7 +150,7 @@ VArray mesh_normals_varray(const MeshComponent &mesh_component, * array and copy the face normal for each of its corners. In this case using the mesh * component's generic domain interpolation is fine, the data will still be normalized, * since the face normal is just copied to every corner. */ - return mesh_component.attribute_try_adapt_domain( + return mesh_component.attributes()->adapt_domain( VArray::ForSpan({(float3 *)BKE_mesh_poly_normals_ensure(&mesh), mesh.totpoly}), ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER); @@ -169,26 +168,6 @@ VArray mesh_normals_varray(const MeshComponent &mesh_component, /** \name Attribute Access * \{ */ -int MeshComponent::attribute_domain_num(const eAttrDomain domain) const -{ - 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_FACE: - return mesh_->totpoly; - default: - break; - } - return 0; -} - namespace blender::bke { template @@ -747,9 +726,10 @@ static GVArray adapt_mesh_domain_edge_to_face(const Mesh &mesh, const GVArray &v } // namespace blender::bke -blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(const blender::GVArray &varray, - const eAttrDomain from_domain, - const eAttrDomain to_domain) const +static blender::GVArray adapt_mesh_attribute_domain(const Mesh &mesh, + const blender::GVArray &varray, + const eAttrDomain from_domain, + const eAttrDomain to_domain) { if (!varray) { return {}; @@ -765,11 +745,11 @@ blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(const blender::G case ATTR_DOMAIN_CORNER: { switch (to_domain) { case ATTR_DOMAIN_POINT: - return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, varray); + return blender::bke::adapt_mesh_domain_corner_to_point(mesh, varray); case ATTR_DOMAIN_FACE: - return blender::bke::adapt_mesh_domain_corner_to_face(*mesh_, varray); + return blender::bke::adapt_mesh_domain_corner_to_face(mesh, varray); case ATTR_DOMAIN_EDGE: - return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, varray); + return blender::bke::adapt_mesh_domain_corner_to_edge(mesh, varray); default: break; } @@ -778,11 +758,11 @@ blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(const blender::G case ATTR_DOMAIN_POINT: { switch (to_domain) { case ATTR_DOMAIN_CORNER: - return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, varray); + return blender::bke::adapt_mesh_domain_point_to_corner(mesh, varray); case ATTR_DOMAIN_FACE: - return blender::bke::adapt_mesh_domain_point_to_face(*mesh_, varray); + return blender::bke::adapt_mesh_domain_point_to_face(mesh, varray); case ATTR_DOMAIN_EDGE: - return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, varray); + return blender::bke::adapt_mesh_domain_point_to_edge(mesh, varray); default: break; } @@ -791,11 +771,11 @@ blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(const blender::G case ATTR_DOMAIN_FACE: { switch (to_domain) { case ATTR_DOMAIN_POINT: - return blender::bke::adapt_mesh_domain_face_to_point(*mesh_, varray); + return blender::bke::adapt_mesh_domain_face_to_point(mesh, varray); case ATTR_DOMAIN_CORNER: - return blender::bke::adapt_mesh_domain_face_to_corner(*mesh_, varray); + return blender::bke::adapt_mesh_domain_face_to_corner(mesh, varray); case ATTR_DOMAIN_EDGE: - return blender::bke::adapt_mesh_domain_face_to_edge(*mesh_, varray); + return blender::bke::adapt_mesh_domain_face_to_edge(mesh, varray); default: break; } @@ -804,11 +784,11 @@ blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(const blender::G case ATTR_DOMAIN_EDGE: { switch (to_domain) { case ATTR_DOMAIN_CORNER: - return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, varray); + return blender::bke::adapt_mesh_domain_edge_to_corner(mesh, varray); case ATTR_DOMAIN_POINT: - return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, varray); + return blender::bke::adapt_mesh_domain_edge_to_point(mesh, varray); case ATTR_DOMAIN_FACE: - return blender::bke::adapt_mesh_domain_edge_to_face(*mesh_, varray); + return blender::bke::adapt_mesh_domain_edge_to_face(mesh, varray); default: break; } @@ -821,20 +801,6 @@ blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(const blender::G return {}; } -static Mesh *get_mesh_from_component_for_write(GeometryComponent &component) -{ - BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH); - MeshComponent &mesh_component = static_cast(component); - return mesh_component.get_for_write(); -} - -static const Mesh *get_mesh_from_component_for_read(const GeometryComponent &component) -{ - BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH); - const MeshComponent &mesh_component = static_cast(component); - return mesh_component.get_for_read(); -} - namespace blender::bke { template @@ -864,9 +830,9 @@ static void set_vertex_position(MVert &vert, float3 position) copy_v3_v3(vert.co, position); } -static void tag_component_positions_changed(GeometryComponent &component) +static void tag_component_positions_changed(void *owner) { - Mesh *mesh = get_mesh_from_component_for_write(component); + Mesh *mesh = static_cast(owner); if (mesh != nullptr) { BKE_mesh_tag_coords_changed(mesh); } @@ -1001,15 +967,13 @@ class VArrayImpl_For_VertexWeights final : public VMutableArrayImpl { */ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { public: - ReadAttributeLookup try_get_for_read(const GeometryComponent &component, - const AttributeIDRef &attribute_id) const final + GAttributeReader try_get_for_read(const void *owner, + const AttributeIDRef &attribute_id) const final { - BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH); if (!attribute_id.is_named()) { return {}; } - const MeshComponent &mesh_component = static_cast(component); - const Mesh *mesh = mesh_component.get_for_read(); + const Mesh *mesh = static_cast(owner); if (mesh == nullptr) { return {}; } @@ -1028,15 +992,12 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { ATTR_DOMAIN_POINT}; } - WriteAttributeLookup try_get_for_write(GeometryComponent &component, - const AttributeIDRef &attribute_id) const final + GAttributeWriter try_get_for_write(void *owner, const AttributeIDRef &attribute_id) const final { - BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH); if (!attribute_id.is_named()) { return {}; } - MeshComponent &mesh_component = static_cast(component); - Mesh *mesh = mesh_component.get_for_write(); + Mesh *mesh = static_cast(owner); if (mesh == nullptr) { return {}; } @@ -1060,14 +1021,12 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { ATTR_DOMAIN_POINT}; } - bool try_delete(GeometryComponent &component, const AttributeIDRef &attribute_id) const final + bool try_delete(void *owner, const AttributeIDRef &attribute_id) const final { - BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH); if (!attribute_id.is_named()) { return false; } - MeshComponent &mesh_component = static_cast(component); - Mesh *mesh = mesh_component.get_for_write(); + Mesh *mesh = static_cast(owner); if (mesh == nullptr) { return true; } @@ -1101,12 +1060,9 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { return true; } - bool foreach_attribute(const GeometryComponent &component, - const AttributeForeachCallback callback) const final + bool foreach_attribute(const void *owner, const AttributeForeachCallback callback) const final { - BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH); - const MeshComponent &mesh_component = static_cast(component); - const Mesh *mesh = mesh_component.get_for_read(); + const Mesh *mesh = static_cast(owner); if (mesh == nullptr) { return true; } @@ -1136,35 +1092,34 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider { { } - GVArray try_get_for_read(const GeometryComponent &component) const final + GVArray try_get_for_read(const void *owner) const final { - const MeshComponent &mesh_component = static_cast(component); - const Mesh *mesh = mesh_component.get_for_read(); + const Mesh *mesh = static_cast(owner); if (mesh == nullptr || mesh->totpoly == 0) { return {}; } return VArray::ForSpan({(float3 *)BKE_mesh_poly_normals_ensure(mesh), mesh->totpoly}); } - WriteAttributeLookup try_get_for_write(GeometryComponent &UNUSED(component)) const final + GAttributeWriter try_get_for_write(void *UNUSED(owner)) const final { return {}; } - bool try_delete(GeometryComponent &UNUSED(component)) const final + bool try_delete(void *UNUSED(owner)) const final { return false; } - bool try_create(GeometryComponent &UNUSED(component), - const AttributeInit &UNUSED(initializer)) const final + bool try_create(void *UNUSED(owner), const AttributeInit &UNUSED(initializer)) const final { return false; } - bool exists(const GeometryComponent &component) const final + bool exists(const void *owner) const final { - return component.attribute_domain_num(ATTR_DOMAIN_FACE) != 0; + const Mesh *mesh = static_cast(owner); + return mesh->totpoly != 0; } }; @@ -1174,34 +1129,42 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider { */ static ComponentAttributeProviders create_attribute_providers_for_mesh() { - static auto update_custom_data_pointers = [](GeometryComponent &component) { - if (Mesh *mesh = get_mesh_from_component_for_write(component)) { - BKE_mesh_update_customdata_pointers(mesh, false); - } + static auto update_custom_data_pointers = [](void *owner) { + Mesh *mesh = static_cast(owner); + BKE_mesh_update_customdata_pointers(mesh, false); }; #define MAKE_MUTABLE_CUSTOM_DATA_GETTER(NAME) \ - [](GeometryComponent &component) -> CustomData * { \ - Mesh *mesh = get_mesh_from_component_for_write(component); \ - return mesh ? &mesh->NAME : nullptr; \ + [](void *owner) -> CustomData * { \ + Mesh *mesh = static_cast(owner); \ + return &mesh->NAME; \ } #define MAKE_CONST_CUSTOM_DATA_GETTER(NAME) \ - [](const GeometryComponent &component) -> const CustomData * { \ - const Mesh *mesh = get_mesh_from_component_for_read(component); \ - return mesh ? &mesh->NAME : nullptr; \ + [](const void *owner) -> const CustomData * { \ + const Mesh *mesh = static_cast(owner); \ + return &mesh->NAME; \ + } +#define MAKE_GET_ELEMENT_NUM_GETTER(NAME) \ + [](const void *owner) -> int { \ + const Mesh *mesh = static_cast(owner); \ + return mesh->NAME; \ } static CustomDataAccessInfo corner_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(ldata), MAKE_CONST_CUSTOM_DATA_GETTER(ldata), + MAKE_GET_ELEMENT_NUM_GETTER(totloop), update_custom_data_pointers}; static CustomDataAccessInfo point_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(vdata), MAKE_CONST_CUSTOM_DATA_GETTER(vdata), + MAKE_GET_ELEMENT_NUM_GETTER(totvert), update_custom_data_pointers}; static CustomDataAccessInfo edge_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(edata), MAKE_CONST_CUSTOM_DATA_GETTER(edata), + MAKE_GET_ELEMENT_NUM_GETTER(totedge), update_custom_data_pointers}; static CustomDataAccessInfo face_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(pdata), MAKE_CONST_CUSTOM_DATA_GETTER(pdata), + MAKE_GET_ELEMENT_NUM_GETTER(totpoly), update_custom_data_pointers}; #undef MAKE_CONST_CUSTOM_DATA_GETTER @@ -1297,13 +1260,72 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() &face_custom_data}); } +static AttributeAccessorFunctions get_mesh_accessor_functions() +{ + static const ComponentAttributeProviders providers = create_attribute_providers_for_mesh(); + AttributeAccessorFunctions fn = + attribute_accessor_functions::accessor_functions_for_providers(); + fn.domain_size = [](const void *owner, const eAttrDomain domain) { + if (owner == nullptr) { + return 0; + } + const Mesh &mesh = *static_cast(owner); + switch (domain) { + case ATTR_DOMAIN_POINT: + return mesh.totvert; + case ATTR_DOMAIN_EDGE: + return mesh.totedge; + case ATTR_DOMAIN_FACE: + return mesh.totpoly; + case ATTR_DOMAIN_CORNER: + return mesh.totloop; + default: + return 0; + } + }; + fn.domain_supported = [](const void *UNUSED(owner), const eAttrDomain domain) { + return ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER); + }; + fn.adapt_domain = [](const void *owner, + const blender::GVArray &varray, + const eAttrDomain from_domain, + const eAttrDomain to_domain) -> blender::GVArray { + if (owner == nullptr) { + return {}; + } + const Mesh &mesh = *static_cast(owner); + return adapt_mesh_attribute_domain(mesh, varray, from_domain, to_domain); + }; + return fn; +} + +static const AttributeAccessorFunctions &get_mesh_accessor_functions_ref() +{ + static const AttributeAccessorFunctions fn = get_mesh_accessor_functions(); + return fn; +} + +AttributeAccessor mesh_attributes(const Mesh &mesh) +{ + return AttributeAccessor(&mesh, get_mesh_accessor_functions_ref()); +} + +MutableAttributeAccessor mesh_attributes_for_write(Mesh &mesh) +{ + return MutableAttributeAccessor(&mesh, get_mesh_accessor_functions_ref()); +} + } // namespace blender::bke -const blender::bke::ComponentAttributeProviders *MeshComponent::get_attribute_providers() const +std::optional MeshComponent::attributes() const +{ + return blender::bke::AttributeAccessor(mesh_, blender::bke::get_mesh_accessor_functions_ref()); +} + +std::optional MeshComponent::attributes_for_write() { - static blender::bke::ComponentAttributeProviders providers = - blender::bke::create_attribute_providers_for_mesh(); - return &providers; + return blender::bke::MutableAttributeAccessor(mesh_, + blender::bke::get_mesh_accessor_functions_ref()); } /** \} */ diff --git a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc index facdbed265d..b439a9ba7f8 100644 --- a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc +++ b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc @@ -2,7 +2,6 @@ #include "DNA_pointcloud_types.h" -#include "BKE_attribute_access.hh" #include "BKE_geometry_set.hh" #include "BKE_lib_id.h" #include "BKE_pointcloud.h" @@ -104,17 +103,6 @@ void PointCloudComponent::ensure_owns_direct_data() /** \name Attribute Access * \{ */ -int PointCloudComponent::attribute_domain_num(const eAttrDomain domain) const -{ - if (pointcloud_ == nullptr) { - return 0; - } - if (domain != ATTR_DOMAIN_POINT) { - return 0; - } - return pointcloud_->totpoint; -} - namespace blender::bke { /** @@ -123,23 +111,22 @@ namespace blender::bke { */ static ComponentAttributeProviders create_attribute_providers_for_point_cloud() { - static auto update_custom_data_pointers = [](GeometryComponent &component) { - PointCloudComponent &pointcloud_component = static_cast(component); - if (PointCloud *pointcloud = pointcloud_component.get_for_write()) { - BKE_pointcloud_update_customdata_pointers(pointcloud); - } + static auto update_custom_data_pointers = [](void *owner) { + PointCloud *pointcloud = static_cast(owner); + BKE_pointcloud_update_customdata_pointers(pointcloud); }; static CustomDataAccessInfo point_access = { - [](GeometryComponent &component) -> CustomData * { - PointCloudComponent &pointcloud_component = static_cast(component); - PointCloud *pointcloud = pointcloud_component.get_for_write(); - return pointcloud ? &pointcloud->pdata : nullptr; + [](void *owner) -> CustomData * { + PointCloud *pointcloud = static_cast(owner); + return &pointcloud->pdata; + }, + [](const void *owner) -> const CustomData * { + const PointCloud *pointcloud = static_cast(owner); + return &pointcloud->pdata; }, - [](const GeometryComponent &component) -> const CustomData * { - const PointCloudComponent &pointcloud_component = static_cast( - component); - const PointCloud *pointcloud = pointcloud_component.get_for_read(); - return pointcloud ? &pointcloud->pdata : nullptr; + [](const void *owner) -> int { + const PointCloud *pointcloud = static_cast(owner); + return pointcloud->totpoint; }, update_custom_data_pointers}; @@ -180,14 +167,67 @@ static ComponentAttributeProviders create_attribute_providers_for_point_cloud() return ComponentAttributeProviders({&position, &radius, &id}, {&point_custom_data}); } +static AttributeAccessorFunctions get_pointcloud_accessor_functions() +{ + static const ComponentAttributeProviders providers = + create_attribute_providers_for_point_cloud(); + AttributeAccessorFunctions fn = + attribute_accessor_functions::accessor_functions_for_providers(); + fn.domain_size = [](const void *owner, const eAttrDomain domain) { + if (owner == nullptr) { + return 0; + } + const PointCloud &pointcloud = *static_cast(owner); + switch (domain) { + case ATTR_DOMAIN_POINT: + return pointcloud.totpoint; + default: + return 0; + } + }; + fn.domain_supported = [](const void *UNUSED(owner), const eAttrDomain domain) { + return domain == ATTR_DOMAIN_POINT; + }; + fn.adapt_domain = [](const void *UNUSED(owner), + const blender::GVArray &varray, + const eAttrDomain from_domain, + const eAttrDomain to_domain) { + if (from_domain == to_domain && from_domain == ATTR_DOMAIN_POINT) { + return varray; + } + return blender::GVArray{}; + }; + return fn; +} + +static const AttributeAccessorFunctions &get_pointcloud_accessor_functions_ref() +{ + static const AttributeAccessorFunctions fn = get_pointcloud_accessor_functions(); + return fn; +} + +AttributeAccessor pointcloud_attributes(const PointCloud &pointcloud) +{ + return AttributeAccessor(&pointcloud, get_pointcloud_accessor_functions_ref()); +} + +MutableAttributeAccessor pointcloud_attributes_for_write(PointCloud &pointcloud) +{ + return MutableAttributeAccessor(&pointcloud, get_pointcloud_accessor_functions_ref()); +} + } // namespace blender::bke -const blender::bke::ComponentAttributeProviders *PointCloudComponent::get_attribute_providers() - const +std::optional PointCloudComponent::attributes() const +{ + return blender::bke::AttributeAccessor(pointcloud_, + blender::bke::get_pointcloud_accessor_functions_ref()); +} + +std::optional PointCloudComponent::attributes_for_write() { - static blender::bke::ComponentAttributeProviders providers = - blender::bke::create_attribute_providers_for_point_cloud(); - return &providers; + return blender::bke::MutableAttributeAccessor( + pointcloud_, blender::bke::get_pointcloud_accessor_functions_ref()); } /** \} */ diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index 70a39acf620..c6fe8eebc7f 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -7,7 +7,6 @@ #include "BLT_translation.h" #include "BKE_attribute.h" -#include "BKE_attribute_access.hh" #include "BKE_curves.hh" #include "BKE_geometry_fields.hh" #include "BKE_geometry_set.hh" @@ -59,6 +58,27 @@ GeometryComponent *GeometryComponent::create(GeometryComponentType component_typ return nullptr; } +int GeometryComponent::attribute_domain_size(const eAttrDomain domain) const +{ + if (this->is_empty()) { + return 0; + } + const std::optional attributes = this->attributes(); + if (attributes.has_value()) { + return attributes->domain_size(domain); + } + return 0; +} + +std::optional GeometryComponent::attributes() const +{ + return std::nullopt; +}; +std::optional GeometryComponent::attributes_for_write() +{ + return std::nullopt; +} + void GeometryComponent::user_add() const { users_.fetch_add(1); @@ -444,11 +464,14 @@ void GeometrySet::attribute_foreach(const Span component_ 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; - }); + const std::optional attributes = component.attributes(); + if (attributes.has_value()) { + attributes->for_all( + [&](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(); @@ -462,7 +485,7 @@ void GeometrySet::gather_attributes_for_propagation( const Span component_types, const GeometryComponentType dst_component_type, bool include_instances, - blender::Map &r_attributes) const + blender::Map &r_attributes) const { using namespace blender; using namespace blender::bke; @@ -475,8 +498,8 @@ void GeometrySet::gather_attributes_for_propagation( [&](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)) { + if (component.attributes()->is_builtin(attribute_id)) { + if (!dummy_component->attributes()->is_builtin(attribute_id)) { /* Don't propagate built-in attributes that are not built-in on the destination * component. */ return; diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index 9cb3e684667..7ebb3e25fd4 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -1209,9 +1209,7 @@ Mesh *BKE_mesh_new_from_object_to_bmain(Main *bmain, BKE_mesh_nomain_to_mesh(mesh, mesh_in_bmain, nullptr, &CD_MASK_MESH, true); /* Anonymous attributes shouldn't exist on original data. */ - MeshComponent component; - component.replace(mesh_in_bmain, GeometryOwnershipType::Editable); - component.attributes_remove_anonymous(); + blender::bke::mesh_attributes_for_write(*mesh_in_bmain).remove_anonymous(); /* User-count is required because so far mesh was in a limbo, where library management does * not perform any user management (i.e. copy of a mesh will not increase users of materials). */ diff --git a/source/blender/blenkernel/intern/mesh_sample.cc b/source/blender/blenkernel/intern/mesh_sample.cc index b792c5c98b9..dd09a3d6917 100644 --- a/source/blender/blenkernel/intern/mesh_sample.cc +++ b/source/blender/blenkernel/intern/mesh_sample.cc @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#include "BKE_attribute_access.hh" #include "BKE_attribute_math.hh" #include "BKE_bvhutils.h" #include "BKE_mesh_runtime.h" @@ -253,12 +252,12 @@ void MeshAttributeInterpolator::sample_data(const GVArray &src, } } -void MeshAttributeInterpolator::sample_attribute(const ReadAttributeLookup &src_attribute, - OutputAttribute &dst_attribute, +void MeshAttributeInterpolator::sample_attribute(const GAttributeReader &src_attribute, + GSpanAttributeWriter &dst_attribute, eAttributeMapMode mode) { if (src_attribute && dst_attribute) { - this->sample_data(src_attribute.varray, src_attribute.domain, mode, dst_attribute.as_span()); + this->sample_data(src_attribute.varray, src_attribute.domain, mode, dst_attribute.span); } } diff --git a/source/blender/blenkernel/intern/spline_base.cc b/source/blender/blenkernel/intern/spline_base.cc index e8c7aff75d1..a674bf7800a 100644 --- a/source/blender/blenkernel/intern/spline_base.cc +++ b/source/blender/blenkernel/intern/spline_base.cc @@ -6,7 +6,6 @@ #include "BLI_task.hh" #include "BLI_timeit.hh" -#include "BKE_attribute_access.hh" #include "BKE_attribute_math.hh" #include "BKE_spline.hh" @@ -21,6 +20,7 @@ using blender::Span; using blender::VArray; using blender::attribute_math::convert_to_static_type; using blender::bke::AttributeIDRef; +using blender::bke::AttributeMetaData; CurveType Spline::type() const { diff --git a/source/blender/draw/intern/draw_cache_impl_curves.cc b/source/blender/draw/intern/draw_cache_impl_curves.cc index 2460482fbbf..d5f188402d6 100644 --- a/source/blender/draw/intern/draw_cache_impl_curves.cc +++ b/source/blender/draw/intern/draw_cache_impl_curves.cc @@ -357,20 +357,20 @@ static void curves_batch_ensure_attribute(const Curves &curves, request.domain == ATTR_DOMAIN_POINT ? curves.geometry.point_num : curves.geometry.curve_num); - CurveComponent component; - component.replace(const_cast(&curves), GeometryOwnershipType::ReadOnly); + const blender::bke::AttributeAccessor attributes = + blender::bke::CurvesGeometry::wrap(curves.geometry).attributes(); /* TODO(@kevindietrich): float4 is used for scalar attributes as the implicit conversion done * by OpenGL to vec4 for a scalar `s` will produce a `vec4(s, 0, 0, 1)`. However, following * the Blender convention, it should be `vec4(s, s, s, 1)`. This could be resolved using a * similar texture state swizzle to map the attribute correctly as for volume attributes, so we * can control the conversion ourselves. */ - blender::VArray attribute = component.attribute_get_for_read( + blender::VArray attribute = attributes.lookup_or_default( request.attribute_name, request.domain, {0.0f, 0.0f, 0.0f, 1.0f}); MutableSpan vbo_span{ static_cast(GPU_vertbuf_get_data(attr_vbo)), - component.attribute_domain_num(request.domain)}; + attributes.domain_size(request.domain)}; attribute.materialize(vbo_span); @@ -629,9 +629,10 @@ static void request_attribute(Curves &curves, const char *name) DRW_Attributes attributes{}; - CurveComponent component; - component.replace(&curves, GeometryOwnershipType::ReadOnly); - std::optional meta_data = component.attribute_get_meta_data(name); + blender::bke::CurvesGeometry &curves_geometry = blender::bke::CurvesGeometry::wrap( + curves.geometry); + std::optional meta_data = + curves_geometry.attributes().lookup_meta_data(name); if (!meta_data) { return; } diff --git a/source/blender/draw/intern/draw_curves.cc b/source/blender/draw/intern/draw_curves.cc index 246f7c843ba..233af08c363 100644 --- a/source/blender/draw/intern/draw_curves.cc +++ b/source/blender/draw/intern/draw_curves.cc @@ -336,9 +336,7 @@ DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object, const blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap( curves_id.geometry); if (curves.curves_num() >= 1) { - CurveComponent curves_component; - curves_component.replace(&curves_id, GeometryOwnershipType::ReadOnly); - blender::VArray radii = curves_component.attribute_get_for_read( + blender::VArray radii = curves.attributes().lookup_or_default( "radius", ATTR_DOMAIN_POINT, 0.005f); const blender::IndexRange first_curve_points = curves.points_for_curve(0); const float first_radius = radii[first_curve_points.first()]; diff --git a/source/blender/editors/curves/intern/curves_ops.cc b/source/blender/editors/curves/intern/curves_ops.cc index 49e21d00195..a4492a1d516 100644 --- a/source/blender/editors/curves/intern/curves_ops.cc +++ b/source/blender/editors/curves/intern/curves_ops.cc @@ -533,9 +533,9 @@ static void snap_curves_to_surface_exec_object(Object &curves_ob, VArraySpan surface_uv_map; if (curves_id.surface_uv_map != nullptr) { - surface_uv_map = surface_mesh_component - .attribute_try_get_for_read( - curves_id.surface_uv_map, ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2) + const bke::AttributeAccessor surface_attributes = bke::mesh_attributes(surface_mesh); + surface_uv_map = surface_attributes + .lookup(curves_id.surface_uv_map, ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2) .typed(); } @@ -756,21 +756,20 @@ static int curves_set_selection_domain_exec(bContext *C, wmOperator *op) curves_id->selection_domain = domain; curves_id->flag |= CV_SCULPT_SELECTION_ENABLED; - CurveComponent component; - component.replace(curves_id, GeometryOwnershipType::Editable); CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry); + bke::MutableAttributeAccessor attributes = curves.attributes_for_write(); if (old_domain == ATTR_DOMAIN_POINT && domain == ATTR_DOMAIN_CURVE) { VArray curve_selection = curves.adapt_domain( curves.selection_point_float(), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); curve_selection.materialize(curves.selection_curve_float_for_write()); - component.attribute_try_delete(".selection_point_float"); + attributes.remove(".selection_point_float"); } else if (old_domain == ATTR_DOMAIN_CURVE && domain == ATTR_DOMAIN_POINT) { VArray point_selection = curves.adapt_domain( curves.selection_curve_float(), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT); point_selection.materialize(curves.selection_point_float_for_write()); - component.attribute_try_delete(".selection_curve_float"); + attributes.remove(".selection_curve_float"); } /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic @@ -900,15 +899,14 @@ static int select_all_exec(bContext *C, wmOperator *op) } for (Curves *curves_id : unique_curves) { + CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry); if (action == SEL_SELECT) { /* As an optimization, just remove the selection attributes when everything is selected. */ - CurveComponent component; - component.replace(curves_id, GeometryOwnershipType::Editable); - component.attribute_try_delete(".selection_point_float"); - component.attribute_try_delete(".selection_curve_float"); + bke::MutableAttributeAccessor attributes = curves.attributes_for_write(); + attributes.remove(".selection_point_float"); + attributes.remove(".selection_curve_float"); } else { - CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry); MutableSpan selection = curves_id->selection_domain == ATTR_DOMAIN_POINT ? curves.selection_point_float_for_write() : curves.selection_curve_float_for_write(); diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc index c7e782b7b89..4cf14334ac7 100644 --- a/source/blender/editors/geometry/geometry_attributes.cc +++ b/source/blender/editors/geometry/geometry_attributes.cc @@ -282,8 +282,7 @@ static int geometry_attribute_convert_exec(bContext *C, wmOperator *op) RNA_enum_get(op->ptr, "mode")); Mesh *mesh = reinterpret_cast(ob_data); - MeshComponent mesh_component; - mesh_component.replace(mesh, GeometryOwnershipType::Editable); + bke::MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh); /* General conversion steps are always the same: * 1. Convert old data to right domain and data type. @@ -301,33 +300,33 @@ static int geometry_attribute_convert_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - GVArray src_varray = mesh_component.attribute_get_for_read(name, dst_domain, dst_type); + GVArray src_varray = attributes.lookup_or_default(name, dst_domain, dst_type); const CPPType &cpp_type = src_varray.type(); void *new_data = MEM_malloc_arrayN(src_varray.size(), cpp_type.size(), __func__); src_varray.materialize_to_uninitialized(new_data); - mesh_component.attribute_try_delete(name); - mesh_component.attribute_try_create(name, dst_domain, dst_type, AttributeInitMove(new_data)); + attributes.remove(name); + attributes.add(name, dst_domain, dst_type, blender::bke::AttributeInitMove(new_data)); break; } case ConvertAttributeMode::UVMap: { MLoopUV *dst_uvs = static_cast( MEM_calloc_arrayN(mesh->totloop, sizeof(MLoopUV), __func__)); - VArray src_varray = mesh_component.attribute_get_for_read( + VArray src_varray = attributes.lookup_or_default( name, ATTR_DOMAIN_CORNER, {0.0f, 0.0f}); for (const int i : IndexRange(mesh->totloop)) { copy_v2_v2(dst_uvs[i].uv, src_varray[i]); } - mesh_component.attribute_try_delete(name); + attributes.remove(name); CustomData_add_layer_named( &mesh->ldata, CD_MLOOPUV, CD_ASSIGN, dst_uvs, mesh->totloop, name.c_str()); break; } case ConvertAttributeMode::VertexGroup: { Array src_weights(mesh->totvert); - VArray src_varray = mesh_component.attribute_get_for_read( + VArray src_varray = attributes.lookup_or_default( name, ATTR_DOMAIN_POINT, 0.0f); src_varray.materialize(src_weights); - mesh_component.attribute_try_delete(name); + attributes.remove(name); bDeformGroup *defgroup = BKE_object_defgroup_new(ob, name.c_str()); const int defgroup_index = BLI_findindex(BKE_id_defgroup_list_get(&mesh->id), defgroup); @@ -652,15 +651,16 @@ bool ED_geometry_attribute_convert(Mesh *mesh, return false; } - MeshComponent mesh_component; - mesh_component.replace(mesh, GeometryOwnershipType::Editable); - GVArray src_varray = mesh_component.attribute_get_for_read(name, new_domain, new_type); + blender::bke::MutableAttributeAccessor attributes = blender::bke::mesh_attributes_for_write( + *mesh); + + GVArray src_varray = attributes.lookup_or_default(name, new_domain, new_type); const CPPType &cpp_type = src_varray.type(); void *new_data = MEM_malloc_arrayN(src_varray.size(), cpp_type.size(), __func__); src_varray.materialize_to_uninitialized(new_data); - mesh_component.attribute_try_delete(name); - mesh_component.attribute_try_create(name, new_domain, new_type, AttributeInitMove(new_data)); + attributes.remove(name); + attributes.add(name, new_domain, new_type, blender::bke::AttributeInitMove(new_data)); int *active_index = BKE_id_attributes_active_index_p(&mesh->id); if (*active_index > 0) { diff --git a/source/blender/editors/object/object_add.cc b/source/blender/editors/object/object_add.cc index a2c08109ec0..66e76addd6f 100644 --- a/source/blender/editors/object/object_add.cc +++ b/source/blender/editors/object/object_add.cc @@ -3177,9 +3177,7 @@ static int object_convert_exec(bContext *C, wmOperator *op) } /* Anonymous attributes shouldn't be available on the applied geometry. */ - MeshComponent component; - component.replace(new_mesh, GeometryOwnershipType::Editable); - component.attributes_remove_anonymous(); + blender::bke::mesh_attributes_for_write(*new_mesh).remove_anonymous(); BKE_object_free_modifiers(newob, 0); /* after derivedmesh calls! */ } diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc index 202c6d96a47..69edd00ae24 100644 --- a/source/blender/editors/object/object_modifier.cc +++ b/source/blender/editors/object/object_modifier.cc @@ -757,9 +757,7 @@ static bool modifier_apply_obdata( BKE_mesh_nomain_to_mesh(mesh_applied, me, ob, &CD_MASK_MESH, true); /* Anonymous attributes shouldn't be available on the applied geometry. */ - MeshComponent component; - component.replace(me, GeometryOwnershipType::Editable); - component.attributes_remove_anonymous(); + blender::bke::mesh_attributes_for_write(*me).remove_anonymous(); if (md_eval->type == eModifierType_Multires) { multires_customdata_delete(me); @@ -828,11 +826,12 @@ static bool modifier_apply_obdata( BKE_report(reports, RPT_ERROR, "Evaluated geometry from modifier does not contain curves"); return false; } - CurveComponent &component = geometry_set.get_component_for_write(); Curves &curves_eval = *geometry_set.get_curves_for_write(); /* Anonymous attributes shouldn't be available on the applied geometry. */ - component.attributes_remove_anonymous(); + blender::bke::CurvesGeometry::wrap(curves_eval.geometry) + .attributes_for_write() + .remove_anonymous(); /* If the modifier's output is a different curves data-block, copy the relevant information to * the original. */ diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc index 401550b3b3a..26145a386f5 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc @@ -176,12 +176,9 @@ struct AddOperationExecutor { /* Find UV map. */ VArraySpan surface_uv_map; if (curves_id_->surface_uv_map != nullptr) { - MeshComponent surface_component; - surface_component.replace(surface_, GeometryOwnershipType::ReadOnly); - surface_uv_map = surface_component - .attribute_try_get_for_read(curves_id_->surface_uv_map, - ATTR_DOMAIN_CORNER) - .typed(); + const bke::AttributeAccessor surface_attributes = bke::mesh_attributes(*surface_); + surface_uv_map = surface_attributes.lookup(curves_id_->surface_uv_map, + ATTR_DOMAIN_CORNER); } /* Find normals. */ diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_density.cc b/source/blender/editors/sculpt_paint/curves_sculpt_density.cc index 826b0611e81..e211a568705 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_density.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_density.cc @@ -64,7 +64,6 @@ struct DensityAddOperationExecutor { Mesh *surface_ = nullptr; Span surface_looptris_; Span corner_normals_su_; - VArraySpan surface_uv_map_; const CurvesSculpt *curves_sculpt_ = nullptr; const Brush *brush_ = nullptr; @@ -228,12 +227,9 @@ struct DensityAddOperationExecutor { /* Find UV map. */ VArraySpan surface_uv_map; if (curves_id_->surface_uv_map != nullptr) { - MeshComponent surface_component; - surface_component.replace(surface_, GeometryOwnershipType::ReadOnly); - surface_uv_map = surface_component - .attribute_try_get_for_read(curves_id_->surface_uv_map, - ATTR_DOMAIN_CORNER) - .typed(); + bke::AttributeAccessor surface_attributes = bke::mesh_attributes(*surface_); + surface_uv_map = surface_attributes.lookup(curves_id_->surface_uv_map, + ATTR_DOMAIN_CORNER); } /* Find normals. */ diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_slide.cc b/source/blender/editors/sculpt_paint/curves_sculpt_slide.cc index dedc880988d..aabe6fd93e4 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_slide.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_slide.cc @@ -148,12 +148,9 @@ struct SlideOperationExecutor { BKE_mesh_runtime_looptri_len(surface_)}; if (curves_id_->surface_uv_map != nullptr) { - MeshComponent surface_component; - surface_component.replace(surface_, GeometryOwnershipType::ReadOnly); - surface_uv_map_ = surface_component - .attribute_try_get_for_read(curves_id_->surface_uv_map, - ATTR_DOMAIN_CORNER) - .typed(); + const bke::AttributeAccessor surface_attributes = bke::mesh_attributes(*surface_); + surface_uv_map_ = surface_attributes.lookup(curves_id_->surface_uv_map, + ATTR_DOMAIN_CORNER); } if (stroke_extension.is_first) { diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc index 50f8854d90f..8b726c7b942 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc +++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc @@ -92,11 +92,9 @@ static bool vertex_paint_from_weight(Object *ob) return false; } - MeshComponent component; - component.replace(me, GeometryOwnershipType::Editable); + bke::MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*me); - bke::WriteAttributeLookup color_attribute = component.attribute_try_get_for_write( - active_color_layer->name); + bke::GAttributeWriter color_attribute = attributes.lookup_for_write(active_color_layer->name); if (!color_attribute) { BLI_assert_unreachable(); return false; @@ -104,7 +102,7 @@ static bool vertex_paint_from_weight(Object *ob) /* Retrieve the vertex group with the domain and type of the existing color * attribute, in order to let the attribute API handle both conversions. */ - const GVArray vertex_group = component.attribute_get_for_read( + const GVArray vertex_group = attributes.lookup( deform_group->name, ATTR_DOMAIN_POINT, bke::cpp_type_to_custom_data_type(color_attribute.varray.type())); @@ -113,14 +111,11 @@ static bool vertex_paint_from_weight(Object *ob) return false; } - GVArraySpan interpolated{component.attribute_try_adapt_domain( - vertex_group, ATTR_DOMAIN_POINT, color_attribute.domain)}; + GVArraySpan interpolated{ + attributes.adapt_domain(vertex_group, ATTR_DOMAIN_POINT, color_attribute.domain)}; color_attribute.varray.set_all(interpolated.data()); - - if (color_attribute.tag_modified_fn) { - color_attribute.tag_modified_fn(); - } + color_attribute.finish(); tag_object_after_update(ob); return true; @@ -167,29 +162,28 @@ static IndexMask get_selected_indices(const Mesh &mesh, Span verts(mesh.mvert, mesh.totvert); Span faces(mesh.mpoly, mesh.totpoly); - MeshComponent component; - component.replace(&const_cast(mesh), GeometryOwnershipType::ReadOnly); + bke::AttributeAccessor attributes = bke::mesh_attributes(mesh); if (mesh.editflag & ME_EDIT_PAINT_FACE_SEL) { - const VArray selection = component.attribute_try_adapt_domain( + const VArray selection = attributes.adapt_domain( VArray::ForFunc(faces.size(), [&](const int i) { return faces[i].flag & ME_FACE_SEL; }), ATTR_DOMAIN_FACE, domain); return index_mask_ops::find_indices_from_virtual_array( - IndexMask(component.attribute_domain_num(domain)), selection, 4096, indices); + IndexMask(attributes.domain_size(domain)), selection, 4096, indices); } if (mesh.editflag & ME_EDIT_PAINT_VERT_SEL) { - const VArray selection = component.attribute_try_adapt_domain( + const VArray selection = attributes.adapt_domain( VArray::ForFunc(verts.size(), [&](const int i) { return verts[i].flag & SELECT; }), ATTR_DOMAIN_POINT, domain); return index_mask_ops::find_indices_from_virtual_array( - IndexMask(component.attribute_domain_num(domain)), selection, 4096, indices); + IndexMask(attributes.domain_size(domain)), selection, 4096, indices); } - return IndexMask(component.attribute_domain_num(domain)); + return IndexMask(attributes.domain_size(domain)); } static void face_corner_color_equalize_vertices(Mesh &mesh, const IndexMask selection) @@ -202,17 +196,15 @@ static void face_corner_color_equalize_vertices(Mesh &mesh, const IndexMask sele return; } - MeshComponent component; - component.replace(&mesh, GeometryOwnershipType::Editable); + bke::AttributeAccessor attributes = bke::mesh_attributes(mesh); - if (component.attribute_get_meta_data(active_color_layer->name)->domain == ATTR_DOMAIN_POINT) { + if (attributes.lookup_meta_data(active_color_layer->name)->domain == ATTR_DOMAIN_POINT) { return; } - GVArray color_attribute_point = component.attribute_try_get_for_read(active_color_layer->name, - ATTR_DOMAIN_POINT); + GVArray color_attribute_point = attributes.lookup(active_color_layer->name, ATTR_DOMAIN_POINT); - GVArray color_attribute_corner = component.attribute_try_adapt_domain( + GVArray color_attribute_corner = attributes.adapt_domain( color_attribute_point, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER); color_attribute_corner.materialize(selection, active_color_layer->data); @@ -278,11 +270,9 @@ static bool transform_active_color(Mesh &mesh, const TransformFn &transform_fn) return false; } - MeshComponent component; - component.replace(&mesh, GeometryOwnershipType::Editable); + bke::MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(mesh); - bke::WriteAttributeLookup color_attribute = component.attribute_try_get_for_write( - active_color_layer->name); + bke::GAttributeWriter color_attribute = attributes.lookup_for_write(active_color_layer->name); if (!color_attribute) { BLI_assert_unreachable(); return false; @@ -310,6 +300,8 @@ static bool transform_active_color(Mesh &mesh, const TransformFn &transform_fn) }); }); + color_attribute.finish(); + DEG_id_tag_update(&mesh.id, 0); return true; diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc index 6be3a65cc1b..2a87c51da5d 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -3,6 +3,7 @@ #include "BLI_index_mask_ops.hh" #include "BLI_virtual_array.hh" +#include "BKE_attribute.hh" #include "BKE_context.h" #include "BKE_editmesh.h" #include "BKE_geometry_fields.hh" @@ -65,7 +66,12 @@ std::unique_ptr ExtraColumns::get_column_values( void GeometryDataSource::foreach_default_column_ids( FunctionRef fn) const { - if (component_->attribute_domain_num(domain_) == 0) { + if (!component_->attributes().has_value()) { + return; + } + const bke::AttributeAccessor attributes = *component_->attributes(); + + if (attributes.domain_size(domain_) == 0) { return; } @@ -74,8 +80,9 @@ void GeometryDataSource::foreach_default_column_ids( } extra_columns_.foreach_default_column_ids(fn); - component_->attribute_foreach( - [&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { + + attributes.for_all( + [&](const bke::AttributeIDRef &attribute_id, const bke::AttributeMetaData &meta_data) { if (meta_data.domain != domain_) { return true; } @@ -114,7 +121,11 @@ void GeometryDataSource::foreach_default_column_ids( std::unique_ptr GeometryDataSource::get_column_values( const SpreadsheetColumnID &column_id) const { - const int domain_num = component_->attribute_domain_num(domain_); + if (!component_->attributes().has_value()) { + return {}; + } + const bke::AttributeAccessor attributes = *component_->attributes(); + const int domain_num = attributes.domain_size(domain_); if (domain_num == 0) { return {}; } @@ -200,7 +211,7 @@ std::unique_ptr GeometryDataSource::get_column_values( } } - bke::ReadAttributeLookup attribute = component_->attribute_try_get_for_read(column_id.name); + bke::GAttributeReader attribute = attributes.lookup(column_id.name); if (!attribute) { return {}; } @@ -214,7 +225,11 @@ std::unique_ptr GeometryDataSource::get_column_values( int GeometryDataSource::tot_rows() const { - return component_->attribute_domain_num(domain_); + if (!component_->attributes().has_value()) { + return {}; + } + const bke::AttributeAccessor attributes = *component_->attributes(); + return attributes.domain_size(domain_); } /** @@ -253,7 +268,7 @@ IndexMask GeometryDataSource::apply_selection_filter(Vector &indices) c const int *orig_indices = (int *)CustomData_get_layer(&mesh_eval->vdata, CD_ORIGINDEX); if (orig_indices != nullptr) { /* Use CD_ORIGINDEX layer if it exists. */ - VArray selection = mesh_component->attribute_try_adapt_domain( + VArray selection = mesh_component->attributes()->adapt_domain( VArray::ForFunc(mesh_eval->totvert, [bm, orig_indices](int vertex_index) -> bool { const int i_orig = orig_indices[vertex_index]; @@ -273,7 +288,7 @@ IndexMask GeometryDataSource::apply_selection_filter(Vector &indices) c if (mesh_eval->totvert == bm->totvert) { /* Use a simple heuristic to match original vertices to evaluated ones. */ - VArray selection = mesh_component->attribute_try_adapt_domain( + VArray selection = mesh_component->attributes()->adapt_domain( VArray::ForFunc(mesh_eval->totvert, [bm](int vertex_index) -> bool { BMVert *vert = bm->vtable[vertex_index]; @@ -511,7 +526,7 @@ static void add_fields_as_extra_columns(SpaceSpreadsheet *sspreadsheet, std::make_unique(component)); const eAttrDomain domain = (eAttrDomain)sspreadsheet->attribute_domain; - const int domain_num = component.attribute_domain_num(domain); + const int domain_num = component.attributes()->domain_size(domain); for (const auto item : fields_to_show.items()) { const StringRef name = item.key; const GField &field = item.value; diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc index ee22f4173ab..aa9b867264a 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc @@ -194,7 +194,7 @@ std::optional GeometryDataSetTreeViewItem::count() const } if (const GeometryComponent *component = geometry.get_component_for_read(component_type_)) { - return component->attribute_domain_num(*domain_); + return component->attribute_domain_size(*domain_); } return 0; diff --git a/source/blender/geometry/intern/mesh_primitive_cuboid.cc b/source/blender/geometry/intern/mesh_primitive_cuboid.cc index 07ac2419ad9..486d8adbf39 100644 --- a/source/blender/geometry/intern/mesh_primitive_cuboid.cc +++ b/source/blender/geometry/intern/mesh_primitive_cuboid.cc @@ -7,7 +7,6 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "BKE_attribute_access.hh" #include "BKE_geometry_set.hh" #include "BKE_mesh.h" @@ -322,11 +321,10 @@ static void calculate_polys(const CuboidConfig &config, static void calculate_uvs(const CuboidConfig &config, Mesh *mesh, const bke::AttributeIDRef &uv_id) { - MeshComponent mesh_component; - mesh_component.replace(mesh, GeometryOwnershipType::Editable); - bke::OutputAttribute_Typed uv_attribute = - mesh_component.attribute_try_get_for_output_only(uv_id, ATTR_DOMAIN_CORNER); - MutableSpan uvs = uv_attribute.as_span(); + bke::MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh); + bke::SpanAttributeWriter uv_attribute = + attributes.lookup_or_add_for_write_only_span(uv_id, ATTR_DOMAIN_CORNER); + MutableSpan uvs = uv_attribute.span; int loop_index = 0; @@ -394,7 +392,7 @@ static void calculate_uvs(const CuboidConfig &config, Mesh *mesh, const bke::Att } } - uv_attribute.save(); + uv_attribute.finish(); } Mesh *create_cuboid_mesh(const float3 &size, diff --git a/source/blender/geometry/intern/mesh_to_curve_convert.cc b/source/blender/geometry/intern/mesh_to_curve_convert.cc index 38f9da2a60c..681dfd15137 100644 --- a/source/blender/geometry/intern/mesh_to_curve_convert.cc +++ b/source/blender/geometry/intern/mesh_to_curve_convert.cc @@ -8,7 +8,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "BKE_attribute_access.hh" +#include "BKE_attribute.hh" #include "BKE_attribute_math.hh" #include "BKE_curves.hh" #include "BKE_geometry_set.hh" @@ -44,14 +44,13 @@ static Curves *create_curve_from_vert_indices(const MeshComponent &mesh_componen curves.cyclic_for_write().fill(false); curves.cyclic_for_write().slice(cyclic_curves).fill(true); - Set source_attribute_ids = mesh_component.attribute_ids(); + bke::MutableAttributeAccessor curves_attributes = curves.attributes_for_write(); + const bke::AttributeAccessor mesh_attributes = *mesh_component.attributes(); - CurveComponent curves_component; - curves_component.replace(curves_id, GeometryOwnershipType::Editable); + Set source_attribute_ids = mesh_attributes.all_ids(); for (const bke::AttributeIDRef &attribute_id : source_attribute_ids) { - if (mesh_component.attribute_is_builtin(attribute_id) && - !curves_component.attribute_is_builtin(attribute_id)) { + if (mesh_attributes.is_builtin(attribute_id) && !curves_attributes.is_builtin(attribute_id)) { /* Don't copy attributes that are built-in on meshes but not on curves. */ continue; } @@ -60,8 +59,7 @@ static Curves *create_curve_from_vert_indices(const MeshComponent &mesh_componen continue; } - const GVArray mesh_attribute = mesh_component.attribute_try_get_for_read(attribute_id, - ATTR_DOMAIN_POINT); + const GVArray mesh_attribute = mesh_attributes.lookup(attribute_id, ATTR_DOMAIN_POINT); /* Some attributes might not exist if they were builtin attribute on domains that don't * have any elements, i.e. a face attribute on the output of the line primitive node. */ if (!mesh_attribute) { @@ -71,10 +69,10 @@ static Curves *create_curve_from_vert_indices(const MeshComponent &mesh_componen /* Copy attribute based on the map for this curve. */ attribute_math::convert_to_static_type(mesh_attribute.type(), [&](auto dummy) { using T = decltype(dummy); - bke::OutputAttribute_Typed attribute = - curves_component.attribute_try_get_for_output_only(attribute_id, ATTR_DOMAIN_POINT); - copy_with_map(mesh_attribute.typed(), vert_indices, attribute.as_span()); - attribute.save(); + bke::SpanAttributeWriter attribute = + curves_attributes.lookup_or_add_for_write_only_span(attribute_id, ATTR_DOMAIN_POINT); + copy_with_map(mesh_attribute.typed(), vert_indices, attribute.span); + attribute.finish(); }); } diff --git a/source/blender/geometry/intern/point_merge_by_distance.cc b/source/blender/geometry/intern/point_merge_by_distance.cc index 6639ff650d3..40bc02cbd34 100644 --- a/source/blender/geometry/intern/point_merge_by_distance.cc +++ b/source/blender/geometry/intern/point_merge_by_distance.cc @@ -104,24 +104,24 @@ PointCloud *point_merge_by_distance(const PointCloudComponent &src_points, point_merge_counts[dst_index]++; } - Set attributes = src_points.attribute_ids(); + const bke::AttributeAccessor src_attributes = *src_points.attributes(); + bke::MutableAttributeAccessor dst_attributes = *dst_points.attributes_for_write(); + Set attributes = src_attributes.all_ids(); /* Transfer the ID attribute if it exists, using the ID of the first merged point. */ if (attributes.contains("id")) { - VArray src = src_points.attribute_get_for_read("id", ATTR_DOMAIN_POINT, 0); - bke::OutputAttribute_Typed dst = dst_points.attribute_try_get_for_output_only( + VArraySpan src = src_attributes.lookup_or_default("id", ATTR_DOMAIN_POINT, 0); + bke::SpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span( "id", ATTR_DOMAIN_POINT); - Span src_ids = src.get_internal_span(); - MutableSpan dst_ids = dst.as_span(); threading::parallel_for(IndexRange(dst_size), 1024, [&](IndexRange range) { for (const int i_dst : range) { const IndexRange points(map_offsets[i_dst], map_offsets[i_dst + 1] - map_offsets[i_dst]); - dst_ids[i_dst] = src_ids[points.first()]; + dst.span[i_dst] = src[points.first()]; } }); - dst.save(); + dst.finish(); attributes.remove_contained("id"); } @@ -131,20 +131,19 @@ PointCloud *point_merge_by_distance(const PointCloudComponent &src_points, continue; } - bke::ReadAttributeLookup src_attribute = src_points.attribute_try_get_for_read(id); + bke::GAttributeReader src_attribute = src_attributes.lookup(id); attribute_math::convert_to_static_type(src_attribute.varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v>) { - bke::OutputAttribute_Typed dst_attribute = - dst_points.attribute_try_get_for_output_only(id, ATTR_DOMAIN_POINT); - Span src = src_attribute.varray.get_internal_span().typed(); - MutableSpan dst = dst_attribute.as_span(); + bke::SpanAttributeWriter dst_attribute = + dst_attributes.lookup_or_add_for_write_only_span(id, ATTR_DOMAIN_POINT); + VArraySpan src = src_attribute.varray.typed(); threading::parallel_for(IndexRange(dst_size), 1024, [&](IndexRange range) { for (const int i_dst : range) { /* Create a separate mixer for every point to avoid allocating temporary buffers * in the mixer the size of the result point cloud and to improve memory locality. */ - attribute_math::DefaultMixer mixer{dst.slice(i_dst, 1)}; + attribute_math::DefaultMixer mixer{dst_attribute.span.slice(i_dst, 1)}; const IndexRange points(map_offsets[i_dst], map_offsets[i_dst + 1] - map_offsets[i_dst]); @@ -157,7 +156,7 @@ PointCloud *point_merge_by_distance(const PointCloudComponent &src_points, } }); - dst_attribute.save(); + dst_attribute.finish(); } }); } diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc index 060a1aa7603..25bf00c5783 100644 --- a/source/blender/geometry/intern/realize_instances.cc +++ b/source/blender/geometry/intern/realize_instances.cc @@ -23,12 +23,13 @@ namespace blender::geometry { using blender::bke::AttributeIDRef; +using blender::bke::AttributeKind; +using blender::bke::AttributeMetaData; using blender::bke::custom_data_type_to_cpp_type; using blender::bke::CustomDataAttributes; +using blender::bke::GSpanAttributeWriter; using blender::bke::object_get_evaluated_geometry_set; -using blender::bke::OutputAttribute; -using blender::bke::OutputAttribute_Typed; -using blender::bke::ReadAttributeLookup; +using blender::bke::SpanAttributeWriter; /** * An ordered set of attribute ids. Attributes are ordered to avoid name lookups in many places. @@ -287,26 +288,27 @@ static void copy_generic_attributes_to_result( const AttributeFallbacksArray &attribute_fallbacks, const OrderedAttributes &ordered_attributes, const FunctionRef &range_fn, - MutableSpan dst_attributes) + MutableSpan dst_attribute_writers) { - threading::parallel_for(dst_attributes.index_range(), 10, [&](const IndexRange attribute_range) { - for (const int attribute_index : attribute_range) { - const eAttrDomain domain = ordered_attributes.kinds[attribute_index].domain; - const IndexRange element_slice = range_fn(domain); - - GMutableSpan dst_span = dst_attributes[attribute_index].slice(element_slice); - if (src_attributes[attribute_index].has_value()) { - threaded_copy(*src_attributes[attribute_index], dst_span); - } - else { - const CPPType &cpp_type = dst_span.type(); - const void *fallback = attribute_fallbacks.array[attribute_index] == nullptr ? - cpp_type.default_value() : - attribute_fallbacks.array[attribute_index]; - threaded_fill({cpp_type, fallback}, dst_span); - } - } - }); + threading::parallel_for( + dst_attribute_writers.index_range(), 10, [&](const IndexRange attribute_range) { + for (const int attribute_index : attribute_range) { + const eAttrDomain domain = ordered_attributes.kinds[attribute_index].domain; + const IndexRange element_slice = range_fn(domain); + + GMutableSpan dst_span = dst_attribute_writers[attribute_index].span.slice(element_slice); + if (src_attributes[attribute_index].has_value()) { + threaded_copy(*src_attributes[attribute_index], dst_span); + } + else { + const CPPType &cpp_type = dst_span.type(); + const void *fallback = attribute_fallbacks.array[attribute_index] == nullptr ? + cpp_type.default_value() : + attribute_fallbacks.array[attribute_index]; + threaded_fill({cpp_type, fallback}, dst_span); + } + } + }); } static void create_result_ids(const RealizeInstancesOptions &options, @@ -361,7 +363,7 @@ static Vector> prepare_attribute_fallbacks( const OrderedAttributes &ordered_attributes) { Vector> attributes_to_override; - const CustomDataAttributes &attributes = instances_component.attributes(); + const CustomDataAttributes &attributes = instances_component.instance_attributes(); attributes.foreach_attribute( [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { const int attribute_index = ordered_attributes.ids.index_of_try(attribute_id); @@ -447,7 +449,7 @@ static void gather_realize_tasks_for_instances(GatherTasksInfo &gather_info, Span stored_instance_ids; if (gather_info.create_id_attribute_on_any_component) { - std::optional ids = instances_component.attributes().get_for_read("id"); + std::optional ids = instances_component.instance_attributes().get_for_read("id"); if (ids.has_value()) { stored_instance_ids = ids->typed(); } @@ -646,34 +648,34 @@ static AllPointCloudsInfo preprocess_pointclouds(const GeometrySet &geometry_set pointcloud_info.pointcloud = pointcloud; /* Access attributes. */ - PointCloudComponent component; - component.replace(const_cast(pointcloud), GeometryOwnershipType::ReadOnly); + bke::AttributeAccessor attributes = bke::pointcloud_attributes(*pointcloud); pointcloud_info.attributes.reinitialize(info.attributes.size()); for (const int attribute_index : info.attributes.index_range()) { const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index]; const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type; const eAttrDomain domain = info.attributes.kinds[attribute_index].domain; - if (component.attribute_exists(attribute_id)) { - GVArray attribute = component.attribute_get_for_read(attribute_id, domain, data_type); + if (attributes.contains(attribute_id)) { + GVArray attribute = attributes.lookup_or_default(attribute_id, domain, data_type); pointcloud_info.attributes[attribute_index].emplace(std::move(attribute)); } } if (info.create_id_attribute) { - ReadAttributeLookup ids_lookup = component.attribute_try_get_for_read("id"); - if (ids_lookup) { - pointcloud_info.stored_ids = ids_lookup.varray.get_internal_span().typed(); + bke::GAttributeReader ids_attribute = attributes.lookup("id"); + if (ids_attribute) { + pointcloud_info.stored_ids = ids_attribute.varray.get_internal_span().typed(); } } } return info; } -static void execute_realize_pointcloud_task(const RealizeInstancesOptions &options, - const RealizePointCloudTask &task, - const OrderedAttributes &ordered_attributes, - PointCloud &dst_pointcloud, - MutableSpan dst_attribute_spans, - MutableSpan all_dst_ids) +static void execute_realize_pointcloud_task( + const RealizeInstancesOptions &options, + const RealizePointCloudTask &task, + const OrderedAttributes &ordered_attributes, + PointCloud &dst_pointcloud, + MutableSpan dst_attribute_writers, + MutableSpan all_dst_ids) { const PointCloudRealizeInfo &pointcloud_info = *task.pointcloud_info; const PointCloud &pointcloud = *pointcloud_info.pointcloud; @@ -699,7 +701,7 @@ static void execute_realize_pointcloud_task(const RealizeInstancesOptions &optio UNUSED_VARS_NDEBUG(domain); return point_slice; }, - dst_attribute_spans); + dst_attribute_writers); } static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &options, @@ -721,42 +723,43 @@ static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &opti PointCloudComponent &dst_component = r_realized_geometry.get_component_for_write(); dst_component.replace(dst_pointcloud); + bke::MutableAttributeAccessor dst_attributes = bke::pointcloud_attributes_for_write( + *dst_pointcloud); /* Prepare id attribute. */ - OutputAttribute_Typed point_ids; - MutableSpan point_ids_span; + SpanAttributeWriter point_ids; if (all_pointclouds_info.create_id_attribute) { - point_ids = dst_component.attribute_try_get_for_output_only("id", ATTR_DOMAIN_POINT); - point_ids_span = point_ids.as_span(); + point_ids = dst_attributes.lookup_or_add_for_write_only_span("id", ATTR_DOMAIN_POINT); } /* Prepare generic output attributes. */ - Vector dst_attributes; - Vector dst_attribute_spans; + Vector dst_attribute_writers; for (const int attribute_index : ordered_attributes.index_range()) { const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index]; const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type; - OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( - attribute_id, ATTR_DOMAIN_POINT, data_type); - dst_attribute_spans.append(dst_attribute.as_span()); - dst_attributes.append(std::move(dst_attribute)); + dst_attribute_writers.append(dst_attributes.lookup_or_add_for_write_only_span( + attribute_id, ATTR_DOMAIN_POINT, data_type)); } /* Actually execute all tasks. */ threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) { for (const int task_index : task_range) { const RealizePointCloudTask &task = tasks[task_index]; - execute_realize_pointcloud_task( - options, task, ordered_attributes, *dst_pointcloud, dst_attribute_spans, point_ids_span); + execute_realize_pointcloud_task(options, + task, + ordered_attributes, + *dst_pointcloud, + dst_attribute_writers, + point_ids.span); } }); - /* Save modified attributes. */ - for (OutputAttribute &dst_attribute : dst_attributes) { - dst_attribute.save(); + /* Tag modified attributes. */ + for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) { + dst_attribute.finish(); } if (point_ids) { - point_ids.save(); + point_ids.finish(); } } @@ -837,22 +840,21 @@ static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set, } /* Access attributes. */ - MeshComponent component; - component.replace(const_cast(mesh), GeometryOwnershipType::ReadOnly); + bke::AttributeAccessor attributes = bke::mesh_attributes(*mesh); mesh_info.attributes.reinitialize(info.attributes.size()); for (const int attribute_index : info.attributes.index_range()) { const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index]; const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type; const eAttrDomain domain = info.attributes.kinds[attribute_index].domain; - if (component.attribute_exists(attribute_id)) { - GVArray attribute = component.attribute_get_for_read(attribute_id, domain, data_type); + if (attributes.contains(attribute_id)) { + GVArray attribute = attributes.lookup_or_default(attribute_id, domain, data_type); mesh_info.attributes[attribute_index].emplace(std::move(attribute)); } } if (info.create_id_attribute) { - ReadAttributeLookup ids_lookup = component.attribute_try_get_for_read("id"); - if (ids_lookup) { - mesh_info.stored_vertex_ids = ids_lookup.varray.get_internal_span().typed(); + bke::GAttributeReader ids_attribute = attributes.lookup("id"); + if (ids_attribute) { + mesh_info.stored_vertex_ids = ids_attribute.varray.get_internal_span().typed(); } } } @@ -863,7 +865,7 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options, const RealizeMeshTask &task, const OrderedAttributes &ordered_attributes, Mesh &dst_mesh, - MutableSpan dst_attribute_spans, + MutableSpan dst_attribute_writers, MutableSpan all_dst_vertex_ids) { const MeshRealizeInfo &mesh_info = *task.mesh_info; @@ -949,7 +951,7 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options, return IndexRange(); } }, - dst_attribute_spans); + dst_attribute_writers); } static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options, @@ -973,6 +975,7 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options, Mesh *dst_mesh = BKE_mesh_new_nomain(tot_vertices, tot_edges, 0, tot_loops, tot_poly); MeshComponent &dst_component = r_realized_geometry.get_component_for_write(); dst_component.replace(dst_mesh); + bke::MutableAttributeAccessor dst_attributes = bke::mesh_attributes_for_write(*dst_mesh); /* Copy settings from the first input geometry set with a mesh. */ const RealizeMeshTask &first_task = tasks.first(); @@ -986,24 +989,19 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options, } /* Prepare id attribute. */ - OutputAttribute_Typed vertex_ids; - MutableSpan vertex_ids_span; + SpanAttributeWriter vertex_ids; if (all_meshes_info.create_id_attribute) { - vertex_ids = dst_component.attribute_try_get_for_output_only("id", ATTR_DOMAIN_POINT); - vertex_ids_span = vertex_ids.as_span(); + vertex_ids = dst_attributes.lookup_or_add_for_write_only_span("id", ATTR_DOMAIN_POINT); } /* Prepare generic output attributes. */ - Vector dst_attributes; - Vector dst_attribute_spans; + Vector dst_attribute_writers; for (const int attribute_index : ordered_attributes.index_range()) { const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index]; const eAttrDomain domain = ordered_attributes.kinds[attribute_index].domain; const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type; - OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( - attribute_id, domain, data_type); - dst_attribute_spans.append(dst_attribute.as_span()); - dst_attributes.append(std::move(dst_attribute)); + dst_attribute_writers.append( + dst_attributes.lookup_or_add_for_write_only_span(attribute_id, domain, data_type)); } /* Actually execute all tasks. */ @@ -1011,16 +1009,16 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options, for (const int task_index : task_range) { const RealizeMeshTask &task = tasks[task_index]; execute_realize_mesh_task( - options, task, ordered_attributes, *dst_mesh, dst_attribute_spans, vertex_ids_span); + options, task, ordered_attributes, *dst_mesh, dst_attribute_writers, vertex_ids.span); } }); - /* Save modified attributes. */ - for (OutputAttribute &dst_attribute : dst_attributes) { - dst_attribute.save(); + /* Tag modified attributes. */ + for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) { + dst_attribute.finish(); } if (vertex_ids) { - vertex_ids.save(); + vertex_ids.finish(); } } @@ -1088,49 +1086,43 @@ static AllCurvesInfo preprocess_curves(const GeometrySet &geometry_set, curve_info.curves = curves_id; /* Access attributes. */ - CurveComponent component; - component.replace(const_cast(curves_id), GeometryOwnershipType::ReadOnly); + bke::AttributeAccessor attributes = curves.attributes(); curve_info.attributes.reinitialize(info.attributes.size()); for (const int attribute_index : info.attributes.index_range()) { const eAttrDomain domain = info.attributes.kinds[attribute_index].domain; const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index]; const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type; - if (component.attribute_exists(attribute_id)) { - GVArray attribute = component.attribute_get_for_read(attribute_id, domain, data_type); + if (attributes.contains(attribute_id)) { + GVArray attribute = attributes.lookup_or_default(attribute_id, domain, data_type); curve_info.attributes[attribute_index].emplace(std::move(attribute)); } } if (info.create_id_attribute) { - ReadAttributeLookup ids_lookup = component.attribute_try_get_for_read("id"); - if (ids_lookup) { - curve_info.stored_ids = ids_lookup.varray.get_internal_span().typed(); + bke::GAttributeReader id_attribute = attributes.lookup("id"); + if (id_attribute) { + curve_info.stored_ids = id_attribute.varray.get_internal_span().typed(); } } /* Retrieve the radius attribute, if it exists. */ - if (component.attribute_exists("radius")) { - curve_info.radius = component - .attribute_get_for_read("radius", ATTR_DOMAIN_POINT, 0.0f) - .get_internal_span(); + if (attributes.contains("radius")) { + curve_info.radius = + attributes.lookup("radius", ATTR_DOMAIN_POINT).get_internal_span(); info.create_radius_attribute = true; } /* Retrieve the resolution attribute, if it exists. */ curve_info.resolution = curves.resolution(); - if (component.attribute_exists("resolution")) { + if (attributes.contains("resolution")) { info.create_resolution_attribute = true; } /* Retrieve handle position attributes, if they exist. */ - if (component.attribute_exists("handle_right")) { - curve_info.handle_left = component - .attribute_get_for_read( - "handle_left", ATTR_DOMAIN_POINT, float3(0)) - .get_internal_span(); - curve_info.handle_right = component - .attribute_get_for_read( - "handle_right", ATTR_DOMAIN_POINT, float3(0)) - .get_internal_span(); + if (attributes.contains("handle_right")) { + curve_info.handle_left = + attributes.lookup("handle_left", ATTR_DOMAIN_POINT).get_internal_span(); + curve_info.handle_right = + attributes.lookup("handle_right", ATTR_DOMAIN_POINT).get_internal_span(); info.create_handle_postion_attributes = true; } } @@ -1142,7 +1134,7 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options, const RealizeCurveTask &task, const OrderedAttributes &ordered_attributes, bke::CurvesGeometry &dst_curves, - MutableSpan dst_attribute_spans, + MutableSpan dst_attribute_writers, MutableSpan all_dst_ids, MutableSpan all_handle_left, MutableSpan all_handle_right, @@ -1220,7 +1212,7 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options, return IndexRange(); } }, - dst_attribute_spans); + dst_attribute_writers); } static void execute_realize_curve_tasks(const RealizeInstancesOptions &options, @@ -1244,57 +1236,45 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options, dst_curves.offsets_for_write().last() = points_num; CurveComponent &dst_component = r_realized_geometry.get_component_for_write(); dst_component.replace(dst_curves_id); + bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write(); /* Prepare id attribute. */ - OutputAttribute_Typed point_ids; - MutableSpan point_ids_span; + SpanAttributeWriter point_ids; if (all_curves_info.create_id_attribute) { - point_ids = dst_component.attribute_try_get_for_output_only("id", ATTR_DOMAIN_POINT); - point_ids_span = point_ids.as_span(); + point_ids = dst_attributes.lookup_or_add_for_write_only_span("id", ATTR_DOMAIN_POINT); } /* Prepare generic output attributes. */ - Vector dst_attributes; - Vector dst_attribute_spans; + Vector dst_attribute_writers; for (const int attribute_index : ordered_attributes.index_range()) { const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index]; const eAttrDomain domain = ordered_attributes.kinds[attribute_index].domain; const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type; - OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( - attribute_id, domain, data_type); - dst_attribute_spans.append(dst_attribute.as_span()); - dst_attributes.append(std::move(dst_attribute)); + dst_attribute_writers.append( + dst_attributes.lookup_or_add_for_write_only_span(attribute_id, domain, data_type)); } /* Prepare handle position attributes if necessary. */ - OutputAttribute_Typed handle_left; - OutputAttribute_Typed handle_right; - MutableSpan handle_left_span; - MutableSpan handle_right_span; + SpanAttributeWriter handle_left; + SpanAttributeWriter handle_right; if (all_curves_info.create_handle_postion_attributes) { - handle_left = dst_component.attribute_try_get_for_output_only("handle_left", - ATTR_DOMAIN_POINT); - handle_right = dst_component.attribute_try_get_for_output_only("handle_right", + handle_left = dst_attributes.lookup_or_add_for_write_only_span("handle_left", ATTR_DOMAIN_POINT); - handle_left_span = handle_left.as_span(); - handle_right_span = handle_right.as_span(); + handle_right = dst_attributes.lookup_or_add_for_write_only_span("handle_right", + ATTR_DOMAIN_POINT); } /* Prepare radius attribute if necessary. */ - OutputAttribute_Typed radius; - MutableSpan radius_span; + SpanAttributeWriter radius; if (all_curves_info.create_radius_attribute) { - radius = dst_component.attribute_try_get_for_output_only("radius", ATTR_DOMAIN_POINT); - radius_span = radius.as_span(); + radius = dst_attributes.lookup_or_add_for_write_only_span("radius", ATTR_DOMAIN_POINT); } /* Prepare resolution attribute if necessary. */ - OutputAttribute_Typed resolution; - MutableSpan resolution_span; + SpanAttributeWriter resolution; if (all_curves_info.create_resolution_attribute) { - resolution = dst_component.attribute_try_get_for_output_only("resolution", - ATTR_DOMAIN_CURVE); - resolution_span = resolution.as_span(); + resolution = dst_attributes.lookup_or_add_for_write_only_span("resolution", + ATTR_DOMAIN_CURVE); } /* Actually execute all tasks. */ @@ -1306,31 +1286,31 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options, task, ordered_attributes, dst_curves, - dst_attribute_spans, - point_ids_span, - handle_left_span, - handle_right_span, - radius_span, - resolution_span); + dst_attribute_writers, + point_ids.span, + handle_left.span, + handle_right.span, + radius.span, + resolution.span); } }); - /* Save modified attributes. */ - for (OutputAttribute &dst_attribute : dst_attributes) { - dst_attribute.save(); + /* Tag modified attributes. */ + for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) { + dst_attribute.finish(); } if (point_ids) { - point_ids.save(); + point_ids.finish(); } if (radius) { - radius.save(); + radius.finish(); } if (resolution) { - resolution.save(); + resolution.finish(); } if (all_curves_info.create_handle_postion_attributes) { - handle_left.save(); - handle_right.save(); + handle_left.finish(); + handle_right.finish(); } } @@ -1345,7 +1325,7 @@ static void remove_id_attribute_from_instances(GeometrySet &geometry_set) geometry_set.modify_geometry_sets([&](GeometrySet &sub_geometry) { if (sub_geometry.has()) { InstancesComponent &component = sub_geometry.get_component_for_write(); - component.attributes().remove("id"); + component.instance_attributes().remove("id"); } }); } diff --git a/source/blender/geometry/intern/resample_curves.cc b/source/blender/geometry/intern/resample_curves.cc index dd1da62408c..c9b8a032ce6 100644 --- a/source/blender/geometry/intern/resample_curves.cc +++ b/source/blender/geometry/intern/resample_curves.cc @@ -92,17 +92,18 @@ static void retrieve_attribute_spans(const Span ids, CurveComponent &dst_component, Vector &src, Vector &dst, - Vector &dst_attributes) + Vector &dst_attributes) { for (const int i : ids.index_range()) { - GVArray src_attribute = src_component.attribute_try_get_for_read(ids[i], ATTR_DOMAIN_POINT); + GVArray src_attribute = src_component.attributes()->lookup(ids[i], ATTR_DOMAIN_POINT); BLI_assert(src_attribute); src.append(src_attribute.get_internal_span()); const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(src_attribute.type()); - bke::OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( - ids[i], ATTR_DOMAIN_POINT, data_type); - dst.append(dst_attribute.as_span()); + bke::GSpanAttributeWriter dst_attribute = + dst_component.attributes_for_write()->lookup_or_add_for_write_only_span( + ids[i], ATTR_DOMAIN_POINT, data_type); + dst.append(dst_attribute.span); dst_attributes.append(std::move(dst_attribute)); } } @@ -111,7 +112,7 @@ struct AttributesForInterpolation : NonCopyable, NonMovable { Vector src; Vector dst; - Vector dst_attributes; + Vector dst_attributes; Vector src_no_interpolation; Vector dst_no_interpolation; @@ -129,8 +130,8 @@ static void gather_point_attributes_to_interpolate(const CurveComponent &src_com VectorSet ids; VectorSet ids_no_interpolation; - src_component.attribute_foreach( - [&](const bke::AttributeIDRef &id, const AttributeMetaData meta_data) { + src_component.attributes()->for_all( + [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData meta_data) { if (meta_data.domain != ATTR_DOMAIN_POINT) { return true; } @@ -311,8 +312,8 @@ static Curves *resample_to_uniform(const CurveComponent &src_component, bke::curves::copy_point_data( src_curves, dst_curves, unselected_ranges, src_positions, dst_positions); - for (bke::OutputAttribute &attribute : attributes.dst_attributes) { - attribute.save(); + for (bke::GSpanAttributeWriter &attribute : attributes.dst_attributes) { + attribute.finish(); } return dst_curves_id; @@ -433,8 +434,8 @@ Curves *resample_to_evaluated(const CurveComponent &src_component, bke::curves::copy_point_data( src_curves, dst_curves, unselected_ranges, src_positions, dst_positions); - for (bke::OutputAttribute &attribute : attributes.dst_attributes) { - attribute.save(); + for (bke::GSpanAttributeWriter &attribute : attributes.dst_attributes) { + attribute.finish(); } return dst_curves_id; diff --git a/source/blender/geometry/intern/set_curve_type.cc b/source/blender/geometry/intern/set_curve_type.cc index d7a5bc9b27d..08888a74973 100644 --- a/source/blender/geometry/intern/set_curve_type.cc +++ b/source/blender/geometry/intern/set_curve_type.cc @@ -290,32 +290,32 @@ struct GenericAttributes : NonCopyable, NonMovable { Vector src; Vector dst; - Vector attributes; + Vector attributes; }; -static void retrieve_generic_point_attributes(const CurveComponent &src_component, - CurveComponent &dst_component, +static void retrieve_generic_point_attributes(const bke::AttributeAccessor &src_attributes, + bke::MutableAttributeAccessor &dst_attributes, GenericAttributes &attributes) { - src_component.attribute_foreach( - [&](const bke::AttributeIDRef &id, const AttributeMetaData meta_data) { + src_attributes.for_all( + [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData meta_data) { if (meta_data.domain != ATTR_DOMAIN_POINT) { /* Curve domain attributes are all copied directly to the result in one step. */ return true; } - if (src_component.attribute_is_builtin(id)) { + if (src_attributes.is_builtin(id)) { if (!(id.is_named() && ELEM(id, "tilt", "radius"))) { return true; } } - GVArray src_attribute = src_component.attribute_try_get_for_read(id, ATTR_DOMAIN_POINT); + GVArray src_attribute = src_attributes.lookup(id, ATTR_DOMAIN_POINT); BLI_assert(src_attribute); attributes.src.append(src_attribute.get_internal_span()); - bke::OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( + bke::GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_span( id, ATTR_DOMAIN_POINT, meta_data.data_type); - attributes.dst.append(dst_attribute.as_span()); + attributes.dst.append(dst_attribute.span); attributes.attributes.append(std::move(dst_attribute)); return true; @@ -367,8 +367,11 @@ static Curves *convert_curves_to_bezier(const CurveComponent &src_component, bke::curves::accumulate_counts_to_offsets(dst_offsets); dst_curves.resize(dst_offsets.last(), dst_curves.curves_num()); + const bke::AttributeAccessor src_attributes = *src_component.attributes(); + bke::MutableAttributeAccessor dst_attributes = *dst_component.attributes_for_write(); + GenericAttributes attributes; - retrieve_generic_point_attributes(src_component, dst_component, attributes); + retrieve_generic_point_attributes(src_attributes, dst_attributes, attributes); MutableSpan dst_positions = dst_curves.positions_for_write(); MutableSpan dst_handles_l = dst_curves.handle_positions_left_for_write(); @@ -494,8 +497,8 @@ static Curves *convert_curves_to_bezier(const CurveComponent &src_component, src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]); } - for (bke::OutputAttribute &attribute : attributes.attributes) { - attribute.save(); + for (bke::GSpanAttributeWriter &attribute : attributes.attributes) { + attribute.finish(); } return dst_curves_id; @@ -524,8 +527,11 @@ static Curves *convert_curves_to_nurbs(const CurveComponent &src_component, bke::curves::accumulate_counts_to_offsets(dst_offsets); dst_curves.resize(dst_offsets.last(), dst_curves.curves_num()); + const bke::AttributeAccessor src_attributes = *src_component.attributes(); + bke::MutableAttributeAccessor dst_attributes = *dst_component.attributes_for_write(); + GenericAttributes attributes; - retrieve_generic_point_attributes(src_component, dst_component, attributes); + retrieve_generic_point_attributes(src_attributes, dst_attributes, attributes); MutableSpan dst_positions = dst_curves.positions_for_write(); @@ -659,8 +665,8 @@ static Curves *convert_curves_to_nurbs(const CurveComponent &src_component, src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]); } - for (bke::OutputAttribute &attribute : attributes.attributes) { - attribute.save(); + for (bke::GSpanAttributeWriter &attribute : attributes.attributes) { + attribute.finish(); } return dst_curves_id; diff --git a/source/blender/geometry/intern/subdivide_curves.cc b/source/blender/geometry/intern/subdivide_curves.cc index 4fb21e53013..914174235cd 100644 --- a/source/blender/geometry/intern/subdivide_curves.cc +++ b/source/blender/geometry/intern/subdivide_curves.cc @@ -79,16 +79,17 @@ static void calculate_result_offsets(const bke::CurvesGeometry &src_curves, struct AttributeTransferData { /* Expect that if an attribute exists, it is stored as a contiguous array internally anyway. */ GVArraySpan src; - bke::OutputAttribute dst; + bke::GSpanAttributeWriter dst; }; -static Vector retrieve_point_attributes(const CurveComponent &src_component, - CurveComponent &dst_component, - const Set &skip = {}) +static Vector retrieve_point_attributes( + const bke::AttributeAccessor &src_attributes, + bke::MutableAttributeAccessor &dst_attributes, + const Set &skip = {}) { Vector attributes; - src_component.attribute_foreach( - [&](const bke::AttributeIDRef &id, const AttributeMetaData meta_data) { + src_attributes.for_all( + [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData meta_data) { if (meta_data.domain != ATTR_DOMAIN_POINT) { /* Curve domain attributes are all copied directly to the result in one step. */ return true; @@ -97,9 +98,9 @@ static Vector retrieve_point_attributes(const CurveCompon return true; } - GVArray src = src_component.attribute_try_get_for_read(id, ATTR_DOMAIN_POINT); + GVArray src = src_attributes.lookup(id, ATTR_DOMAIN_POINT); BLI_assert(src); - bke::OutputAttribute dst = dst_component.attribute_try_get_for_output_only( + bke::GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span( id, ATTR_DOMAIN_POINT, meta_data.data_type); BLI_assert(dst); attributes.append({std::move(src), std::move(dst)}); @@ -384,28 +385,27 @@ Curves *subdivide_curves(const CurveComponent &src_component, dst_curves.resize(dst_curves.offsets().last(), dst_curves.curves_num()); + const bke::AttributeAccessor src_attributes = *src_component.attributes(); + bke::MutableAttributeAccessor dst_attributes = *dst_component.attributes_for_write(); + auto subdivide_catmull_rom = [&](IndexMask selection) { - for (auto &attribute : retrieve_point_attributes(src_component, dst_component)) { + for (auto &attribute : retrieve_point_attributes(src_attributes, dst_attributes)) { subdivide_attribute_catmull_rom(src_curves, dst_curves, selection, point_offsets, cyclic, attribute.src, - attribute.dst.as_span()); - attribute.dst.save(); + attribute.dst.span); + attribute.dst.finish(); } }; auto subdivide_poly = [&](IndexMask selection) { - for (auto &attribute : retrieve_point_attributes(src_component, dst_component)) { - subdivide_attribute_linear(src_curves, - dst_curves, - selection, - point_offsets, - attribute.src, - attribute.dst.as_span()); - attribute.dst.save(); + for (auto &attribute : retrieve_point_attributes(src_attributes, dst_attributes)) { + subdivide_attribute_linear( + src_curves, dst_curves, selection, point_offsets, attribute.src, attribute.dst.span); + attribute.dst.finish(); } }; @@ -443,20 +443,16 @@ Curves *subdivide_curves(const CurveComponent &src_component, } }); - for (auto &attribute : retrieve_point_attributes(src_component, - dst_component, + for (auto &attribute : retrieve_point_attributes(src_attributes, + dst_attributes, {"position", "handle_type_left", "handle_type_right", "handle_right", "handle_left"})) { - subdivide_attribute_linear(src_curves, - dst_curves, - selection, - point_offsets, - attribute.src, - attribute.dst.as_span()); - attribute.dst.save(); + subdivide_attribute_linear( + src_curves, dst_curves, selection, point_offsets, attribute.src, attribute.dst.span); + attribute.dst.finish(); } }; @@ -473,10 +469,10 @@ Curves *subdivide_curves(const CurveComponent &src_component, subdivide_nurbs); if (!unselected_ranges.is_empty()) { - for (auto &attribute : retrieve_point_attributes(src_component, dst_component)) { + for (auto &attribute : retrieve_point_attributes(src_attributes, dst_attributes)) { bke::curves::copy_point_data( - src_curves, dst_curves, unselected_ranges, attribute.src, attribute.dst.as_span()); - attribute.dst.save(); + src_curves, dst_curves, unselected_ranges, attribute.src, attribute.dst.span); + attribute.dst.finish(); } } diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc index cb95c561547..731587bfcea 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc @@ -254,9 +254,8 @@ void OBJWriter::write_vertex_coords(FormatHandler &fh, colors_layer = BKE_id_attributes_active_color_get(&mesh->id); } if (write_colors && (colors_layer != nullptr)) { - MeshComponent component; - component.replace(mesh, GeometryOwnershipType::ReadOnly); - VArray attribute = component.attribute_get_for_read( + const bke::AttributeAccessor attributes = bke::mesh_attributes(*mesh); + const VArray attribute = attributes.lookup_or_default( colors_layer->name, ATTR_DOMAIN_POINT, {0.0f, 0.0f, 0.0f, 0.0f}); BLI_assert(tot_count == attribute.size()); diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index a63a89e076b..885d2f901ec 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -109,7 +109,7 @@ using blender::Span; using blender::StringRef; using blender::StringRefNull; using blender::Vector; -using blender::bke::OutputAttribute; +using blender::bke::AttributeMetaData; using blender::fn::Field; using blender::fn::GField; using blender::fn::ValueOrField; @@ -999,22 +999,27 @@ static Vector compute_attributes_to_store( continue; } const GeometryComponent &component = *geometry.get_component_for_read(component_type); + if (component.is_empty()) { + continue; + } + const blender::bke::AttributeAccessor attributes = *component.attributes(); for (const auto item : outputs_by_domain.items()) { const eAttrDomain domain = item.key; const Span outputs_info = item.value; - if (!component.attribute_domain_supported(domain)) { + if (!attributes.domain_supported(domain)) { continue; } - const int domain_num = component.attribute_domain_num(domain); + const int domain_size = attributes.domain_size(domain); blender::bke::GeometryComponentFieldContext field_context{component, domain}; - blender::fn::FieldEvaluator field_evaluator{field_context, domain_num}; + blender::fn::FieldEvaluator field_evaluator{field_context, domain_size}; for (const OutputAttributeInfo &output_info : outputs_info) { const CPPType &type = output_info.field.cpp_type(); OutputAttributeToStore store{ component_type, domain, output_info.name, - GMutableSpan{type, MEM_malloc_arrayN(domain_num, type.size(), __func__), domain_num}}; + GMutableSpan{ + type, MEM_malloc_arrayN(domain_size, type.size(), __func__), domain_size}}; field_evaluator.add_with_destination(output_info.field, store.data); attributes_to_store.append(store); } @@ -1029,33 +1034,33 @@ static void store_computed_output_attributes( { for (const OutputAttributeToStore &store : attributes_to_store) { GeometryComponent &component = geometry.get_component_for_write(store.component_type); + blender::bke::MutableAttributeAccessor attributes = *component.attributes_for_write(); + const eCustomDataType data_type = blender::bke::cpp_type_to_custom_data_type( store.data.type()); - const std::optional meta_data = component.attribute_get_meta_data( - store.name); + const std::optional meta_data = attributes.lookup_meta_data(store.name); /* Attempt to remove the attribute if it already exists but the domain and type don't match. * Removing the attribute won't succeed if it is built in and non-removable. */ if (meta_data.has_value() && (meta_data->domain != store.domain || meta_data->data_type != data_type)) { - component.attribute_try_delete(store.name); + attributes.remove(store.name); } /* Try to create the attribute reusing the stored buffer. This will only succeed if the * attribute didn't exist before, or if it existed but was removed above. */ - if (component.attribute_try_create( - store.name, - store.domain, - blender::bke::cpp_type_to_custom_data_type(store.data.type()), - AttributeInitMove(store.data.data()))) { + if (attributes.add(store.name, + store.domain, + blender::bke::cpp_type_to_custom_data_type(store.data.type()), + blender::bke::AttributeInitMove(store.data.data()))) { continue; } - OutputAttribute attribute = component.attribute_try_get_for_output_only( + blender::bke::GAttributeWriter attribute = attributes.lookup_or_add_for_write( store.name, store.domain, data_type); if (attribute) { - attribute.varray().set_all(store.data.data()); - attribute.save(); + attribute.varray.set_all(store.data.data()); + attribute.finish(); } /* We were unable to reuse the data, so it must be destructed and freed. */ diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index c2dd1cd3ab5..0d5ba6cf5db 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -5,7 +5,6 @@ #include "FN_field.hh" #include "FN_multi_function_builder.hh" -#include "BKE_attribute_access.hh" #include "BKE_geometry_fields.hh" #include "BKE_geometry_set.hh" @@ -20,16 +19,22 @@ struct ModifierData; namespace blender::nodes { using bke::AnonymousAttributeFieldInput; +using bke::AttributeAccessor; using bke::AttributeFieldInput; using bke::AttributeIDRef; +using bke::AttributeKind; +using bke::AttributeMetaData; +using bke::AttributeReader; +using bke::AttributeWriter; +using bke::GAttributeReader; +using bke::GAttributeWriter; using bke::GeometryComponentFieldContext; using bke::GeometryFieldInput; -using bke::OutputAttribute; -using bke::OutputAttribute_Typed; -using bke::ReadAttributeLookup; +using bke::GSpanAttributeWriter; +using bke::MutableAttributeAccessor; +using bke::SpanAttributeWriter; using bke::StrongAnonymousAttributeID; using bke::WeakAnonymousAttributeID; -using bke::WriteAttributeLookup; using fn::Field; using fn::FieldContext; using fn::FieldEvaluator; diff --git a/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc b/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc index be7b3446125..58fbfb5a000 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc @@ -217,16 +217,20 @@ template class AccumulateFieldInput final : public GeometryFieldInpu IndexMask UNUSED(mask)) const final { const GeometryComponentFieldContext field_context{component, source_domain_}; - const int domain_num = component.attribute_domain_num(field_context.domain()); + const int domain_size = component.attribute_domain_size(field_context.domain()); + if (domain_size == 0) { + return {}; + } + const AttributeAccessor attributes = *component.attributes(); - fn::FieldEvaluator evaluator{field_context, domain_num}; + fn::FieldEvaluator evaluator{field_context, domain_size}; evaluator.add(input_); evaluator.add(group_index_); evaluator.evaluate(); const VArray values = evaluator.get_evaluated(0); const VArray group_indices = evaluator.get_evaluated(1); - Array accumulations_out(domain_num); + Array accumulations_out(domain_size); if (group_indices.is_single()) { T accumulation = T(); @@ -261,7 +265,7 @@ template class AccumulateFieldInput final : public GeometryFieldInpu } } - return component.attribute_try_adapt_domain( + return attributes.adapt_domain( VArray::ForContainer(std::move(accumulations_out)), source_domain_, domain); } @@ -303,9 +307,13 @@ template class TotalFieldInput final : public GeometryFieldInput { IndexMask UNUSED(mask)) const final { const GeometryComponentFieldContext field_context{component, source_domain_}; - const int domain_num = component.attribute_domain_num(field_context.domain()); + const int domain_size = component.attribute_domain_size(field_context.domain()); + if (domain_size == 0) { + return {}; + } + const AttributeAccessor attributes = *component.attributes(); - fn::FieldEvaluator evaluator{field_context, domain_num}; + fn::FieldEvaluator evaluator{field_context, domain_size}; evaluator.add(input_); evaluator.add(group_index_); evaluator.evaluate(); @@ -317,10 +325,10 @@ template class TotalFieldInput final : public GeometryFieldInput { for (const int i : values.index_range()) { accumulation = values[i] + accumulation; } - return VArray::ForSingle(accumulation, domain_num); + return VArray::ForSingle(accumulation, domain_size); } - Array accumulations_out(domain_num); + Array accumulations_out(domain_size); Map accumulations; for (const int i : values.index_range()) { T &value = accumulations.lookup_or_add_default(group_indices[i]); @@ -330,7 +338,7 @@ template class TotalFieldInput final : public GeometryFieldInput { accumulations_out[i] = accumulations.lookup(group_indices[i]); } - return component.attribute_try_adapt_domain( + return attributes.adapt_domain( VArray::ForContainer(std::move(accumulations_out)), source_domain_, domain); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc index 496fb081d6b..9f317075bb5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc @@ -111,19 +111,26 @@ static void try_capture_field_on_geometry(GeometryComponent &component, const eAttrDomain domain, const GField &field) { + const int domain_size = component.attribute_domain_size(domain); + if (domain_size == 0) { + return; + } GeometryComponentFieldContext field_context{component, domain}; - const int domain_num = component.attribute_domain_num(domain); - const IndexMask mask{IndexMask(domain_num)}; + MutableAttributeAccessor attributes = *component.attributes_for_write(); + const IndexMask mask{IndexMask(domain_size)}; const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(field.cpp_type()); - OutputAttribute output_attribute = component.attribute_try_get_for_output_only( + GAttributeWriter output_attribute = attributes.lookup_or_add_for_write( attribute_id, domain, data_type); + if (!output_attribute) { + return; + } fn::FieldEvaluator evaluator{field_context, &mask}; - evaluator.add_with_destination(field, output_attribute.varray()); + evaluator.add_with_destination(field, output_attribute.varray); evaluator.evaluate(); - output_attribute.save(); + output_attribute.finish(); } static StringRefNull identifier_suffix(eCustomDataType data_type) diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc index 8ab0eb678e7..7e4904a7a6a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc @@ -72,11 +72,11 @@ static void node_geo_exec(GeoNodeExecParams params) case GEO_COMPONENT_TYPE_MESH: { if (geometry_set.has_mesh()) { const MeshComponent *component = geometry_set.get_component_for_read(); - params.set_output("Point Count", component->attribute_domain_num(ATTR_DOMAIN_POINT)); - params.set_output("Edge Count", component->attribute_domain_num(ATTR_DOMAIN_EDGE)); - params.set_output("Face Count", component->attribute_domain_num(ATTR_DOMAIN_FACE)); - params.set_output("Face Corner Count", - component->attribute_domain_num(ATTR_DOMAIN_CORNER)); + const AttributeAccessor attributes = *component->attributes(); + params.set_output("Point Count", attributes.domain_size(ATTR_DOMAIN_POINT)); + params.set_output("Edge Count", attributes.domain_size(ATTR_DOMAIN_EDGE)); + params.set_output("Face Count", attributes.domain_size(ATTR_DOMAIN_FACE)); + params.set_output("Face Corner Count", attributes.domain_size(ATTR_DOMAIN_CORNER)); } else { params.set_default_remaining_outputs(); @@ -86,8 +86,9 @@ static void node_geo_exec(GeoNodeExecParams params) case GEO_COMPONENT_TYPE_CURVE: { if (geometry_set.has_curves()) { const CurveComponent *component = geometry_set.get_component_for_read(); - params.set_output("Point Count", component->attribute_domain_num(ATTR_DOMAIN_POINT)); - params.set_output("Spline Count", component->attribute_domain_num(ATTR_DOMAIN_CURVE)); + const AttributeAccessor attributes = *component->attributes(); + params.set_output("Point Count", attributes.domain_size(ATTR_DOMAIN_POINT)); + params.set_output("Spline Count", attributes.domain_size(ATTR_DOMAIN_CURVE)); } else { params.set_default_remaining_outputs(); @@ -98,7 +99,7 @@ static void node_geo_exec(GeoNodeExecParams params) if (geometry_set.has_pointcloud()) { const PointCloudComponent *component = geometry_set.get_component_for_read(); - params.set_output("Point Count", component->attribute_domain_num(ATTR_DOMAIN_POINT)); + params.set_output("Point Count", component->attributes()->domain_size(ATTR_DOMAIN_POINT)); } else { params.set_default_remaining_outputs(); @@ -109,7 +110,8 @@ static void node_geo_exec(GeoNodeExecParams params) if (geometry_set.has_instances()) { const InstancesComponent *component = geometry_set.get_component_for_read(); - params.set_output("Instance Count", component->attribute_domain_num(ATTR_DOMAIN_INSTANCE)); + params.set_output("Instance Count", + component->attributes()->domain_size(ATTR_DOMAIN_INSTANCE)); } else { params.set_default_remaining_outputs(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc index 08e72dae8f6..34e28e50c81 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc @@ -195,9 +195,13 @@ static void node_geo_exec(GeoNodeExecParams params) const Field input_field = params.get_input>("Attribute"); Vector data; for (const GeometryComponent *component : components) { - if (component->attribute_domain_supported(domain)) { + const std::optional attributes = component->attributes(); + if (!attributes.has_value()) { + continue; + } + if (attributes->domain_supported(domain)) { GeometryComponentFieldContext field_context{*component, domain}; - const int domain_num = component->attribute_domain_num(domain); + const int domain_num = attributes->domain_size(domain); fn::FieldEvaluator data_evaluator{field_context, domain_num}; data_evaluator.add(input_field); @@ -273,9 +277,13 @@ static void node_geo_exec(GeoNodeExecParams params) const Field input_field = params.get_input>("Attribute_001"); Vector data; for (const GeometryComponent *component : components) { - if (component->attribute_domain_supported(domain)) { + const std::optional attributes = component->attributes(); + if (!attributes.has_value()) { + continue; + } + if (attributes->domain_supported(domain)) { GeometryComponentFieldContext field_context{*component, domain}; - const int domain_num = component->attribute_domain_num(domain); + const int domain_num = attributes->domain_size(domain); fn::FieldEvaluator data_evaluator{field_context, domain_num}; data_evaluator.add(input_field); diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc index 81cce1fc5da..69938f3e447 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc @@ -154,17 +154,15 @@ static void node_geo_exec(GeoNodeExecParams params) /* Store intersecting edges in attribute. */ if (attribute_outputs.intersecting_edges_id) { - MeshComponent mesh_component; - mesh_component.replace(result, GeometryOwnershipType::Editable); - OutputAttribute_Typed attribute = mesh_component.attribute_try_get_for_output_only( + MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*result); + SpanAttributeWriter selection = attributes.lookup_or_add_for_write_only_span( attribute_outputs.intersecting_edges_id.get(), ATTR_DOMAIN_EDGE); - MutableSpan selection = attribute.as_span(); - selection.fill(false); + + selection.span.fill(false); for (const int i : intersecting_edges) { - selection[i] = true; + selection.span[i] = true; } - - attribute.save(); + selection.finish(); params.set_output( "Intersecting Edges", diff --git a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc index 045206d04cd..489b618b8be 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc @@ -143,7 +143,8 @@ static Mesh *compute_hull(const GeometrySet &geometry_set) if (geometry_set.has_mesh()) { count++; const MeshComponent *component = geometry_set.get_component_for_read(); - total_num += component->attribute_domain_num(ATTR_DOMAIN_POINT); + const Mesh *mesh = component->get_for_read(); + total_num += mesh->totvert; } if (geometry_set.has_pointcloud()) { @@ -151,10 +152,9 @@ static Mesh *compute_hull(const GeometrySet &geometry_set) span_count++; const PointCloudComponent *component = geometry_set.get_component_for_read(); - VArray varray = component->attribute_get_for_read( - "position", ATTR_DOMAIN_POINT, {0, 0, 0}); - total_num += varray.size(); - positions_span = varray.get_internal_span(); + const PointCloud *pointcloud = component->get_for_read(); + positions_span = {reinterpret_cast(pointcloud->co), pointcloud->totpoint}; + total_num += pointcloud->totpoint; } if (geometry_set.has_curves()) { @@ -181,8 +181,8 @@ static Mesh *compute_hull(const GeometrySet &geometry_set) if (geometry_set.has_mesh()) { const MeshComponent *component = geometry_set.get_component_for_read(); - VArray varray = component->attribute_get_for_read( - "position", ATTR_DOMAIN_POINT, {0, 0, 0}); + const VArray varray = component->attributes()->lookup("position", + ATTR_DOMAIN_POINT); varray.materialize(positions.as_mutable_span().slice(offset, varray.size())); offset += varray.size(); } @@ -190,8 +190,8 @@ static Mesh *compute_hull(const GeometrySet &geometry_set) if (geometry_set.has_pointcloud()) { const PointCloudComponent *component = geometry_set.get_component_for_read(); - VArray varray = component->attribute_get_for_read( - "position", ATTR_DOMAIN_POINT, {0, 0, 0}); + const VArray varray = component->attributes()->lookup("position", + ATTR_DOMAIN_POINT); varray.materialize(positions.as_mutable_span().slice(offset, varray.size())); offset += varray.size(); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc index fb8a488ddae..e200350dc18 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc @@ -581,8 +581,8 @@ static void calculate_curve_fillet(GeometrySet &geometry_set, CurveComponent &component = geometry_set.get_component_for_write(); GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT}; - const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_POINT); - fn::FieldEvaluator field_evaluator{field_context, domain_num}; + const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT); + fn::FieldEvaluator field_evaluator{field_context, domain_size}; field_evaluator.add(radius_field); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc index 91ba5f2845f..286d9993d0e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc @@ -61,13 +61,13 @@ static Curves *create_star_curve(const float inner_radius, static void create_selection_output(CurveComponent &component, StrongAnonymousAttributeID &r_attribute) { - OutputAttribute_Typed attribute = component.attribute_try_get_for_output_only( - r_attribute.get(), ATTR_DOMAIN_POINT); - MutableSpan selection = attribute.as_span(); - for (int i : selection.index_range()) { - selection[i] = i % 2 == 0; + SpanAttributeWriter selection = + component.attributes_for_write()->lookup_or_add_for_write_only_span(r_attribute.get(), + ATTR_DOMAIN_POINT); + for (int i : selection.span.index_range()) { + selection.span[i] = i % 2 == 0; } - attribute.save(); + selection.finish(); } static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc index 64a174df599..de29735bd2d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc @@ -27,9 +27,9 @@ static void node_geo_exec(GeoNodeExecParams params) Field selection_field = params.get_input>("Selection"); const CurveComponent &component = *geometry_set.get_component_for_read(); GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE}; - const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_CURVE); + const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE); - fn::FieldEvaluator selection_evaluator{field_context, domain_num}; + fn::FieldEvaluator selection_evaluator{field_context, domain_size}; selection_evaluator.add(selection_field); selection_evaluator.evaluate(); const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handle_type.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handle_type.cc index 469d8d8d13b..f7ba724c377 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handle_type.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handle_type.cc @@ -98,8 +98,8 @@ static void node_geo_exec(GeoNodeExecParams params) } has_curves = true; const CurveComponent &component = *geometry_set.get_component_for_read(); - if (!component.attribute_exists("handle_type_left") || - !component.attribute_exists("handle_type_right")) { + const AttributeAccessor attributes = *component.attributes(); + if (!attributes.contains("handle_type_left") || !attributes.contains("handle_type_right")) { return; } has_bezier = true; diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc index 7d83b4b3ecb..6c4fb2e0855 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc @@ -126,19 +126,18 @@ static GMutableSpan ensure_point_attribute(PointCloudComponent &points, const AttributeIDRef &attribute_id, const eCustomDataType data_type) { - points.attribute_try_create(attribute_id, ATTR_DOMAIN_POINT, data_type, AttributeInitDefault()); - WriteAttributeLookup attribute = points.attribute_try_get_for_write(attribute_id); - BLI_assert(attribute); - return attribute.varray.get_internal_span(); + return points.attributes_for_write() + ->lookup_or_add_for_write(attribute_id, ATTR_DOMAIN_POINT, data_type) + .varray.get_internal_span(); } template static MutableSpan ensure_point_attribute(PointCloudComponent &points, const AttributeIDRef &attribute_id) { - GMutableSpan attribute = ensure_point_attribute( - points, attribute_id, bke::cpp_type_to_custom_data_type(CPPType::get())); - return attribute.typed(); + return points.attributes_for_write() + ->lookup_or_add_for_write(attribute_id, ATTR_DOMAIN_POINT) + .varray.get_internal_span(); } namespace { diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc index 2b90428acb1..00a79168087 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc @@ -506,9 +506,9 @@ static void geometry_set_curve_trim(GeometrySet &geometry_set, CurveComponent &component = geometry_set.get_component_for_write(); GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE}; - const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_CURVE); + const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE); - fn::FieldEvaluator evaluator{field_context, domain_num}; + fn::FieldEvaluator evaluator{field_context, domain_size}; evaluator.add(start_field); evaluator.add(end_field); evaluator.evaluate(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc index 60b5f0383ca..ab7ddfa71f1 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc @@ -252,10 +252,8 @@ static void node_geo_exec(GeoNodeExecParams params) BKE_mesh_wrapper_ensure_mdata(surface_mesh_eval); - MeshComponent mesh_eval; - mesh_eval.replace(surface_mesh_eval, GeometryOwnershipType::ReadOnly); - MeshComponent mesh_orig; - mesh_orig.replace(surface_mesh_orig, GeometryOwnershipType::ReadOnly); + const AttributeAccessor mesh_attributes_eval = bke::mesh_attributes(*surface_mesh_eval); + const AttributeAccessor mesh_attributes_orig = bke::mesh_attributes(*surface_mesh_orig); Curves &curves_id = *curves_geometry.get_curves_for_write(); CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry); @@ -266,7 +264,7 @@ static void node_geo_exec(GeoNodeExecParams params) params.error_message_add(NodeWarningType::Error, message); return; } - if (!mesh_eval.attribute_exists(uv_map_name)) { + if (!mesh_attributes_eval.contains(uv_map_name)) { pass_through_input(); char *message = BLI_sprintfN(TIP_("Evaluated surface missing UV map: %s."), uv_map_name.c_str()); @@ -274,7 +272,7 @@ static void node_geo_exec(GeoNodeExecParams params) MEM_freeN(message); return; } - if (!mesh_orig.attribute_exists(uv_map_name)) { + if (!mesh_attributes_orig.contains(uv_map_name)) { pass_through_input(); char *message = BLI_sprintfN(TIP_("Original surface missing UV map: %s."), uv_map_name.c_str()); @@ -282,7 +280,7 @@ static void node_geo_exec(GeoNodeExecParams params) MEM_freeN(message); return; } - if (!mesh_eval.attribute_exists(rest_position_name)) { + if (!mesh_attributes_eval.contains(rest_position_name)) { pass_through_input(); params.error_message_add(NodeWarningType::Error, TIP_("Evaluated surface missing attribute: rest_position.")); @@ -294,12 +292,12 @@ static void node_geo_exec(GeoNodeExecParams params) TIP_("Curves are not attached to any UV map.")); return; } - const VArraySpan uv_map_orig = mesh_orig.attribute_get_for_read( - uv_map_name, ATTR_DOMAIN_CORNER, {0.0f, 0.0f}); - const VArraySpan uv_map_eval = mesh_eval.attribute_get_for_read( - uv_map_name, ATTR_DOMAIN_CORNER, {0.0f, 0.0f}); - const VArraySpan rest_positions = mesh_eval.attribute_get_for_read( - rest_position_name, ATTR_DOMAIN_POINT, {0.0f, 0.0f, 0.0f}); + const VArraySpan uv_map_orig = mesh_attributes_orig.lookup(uv_map_name, + ATTR_DOMAIN_CORNER); + const VArraySpan uv_map_eval = mesh_attributes_eval.lookup(uv_map_name, + ATTR_DOMAIN_CORNER); + const VArraySpan rest_positions = mesh_attributes_eval.lookup(rest_position_name, + ATTR_DOMAIN_POINT); const Span surface_uv_coords = curves.surface_uv_coords(); const Span looptris_orig{BKE_mesh_runtime_looptri_ensure(surface_mesh_orig), diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc index 68489d1b9a6..408596b65aa 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc @@ -49,7 +49,7 @@ static void copy_attributes(const Map &attributes { for (Map::Item entry : attributes.items()) { const AttributeIDRef attribute_id = entry.key; - ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(attribute_id); + GAttributeReader attribute = in_component.attributes()->lookup(attribute_id); if (!attribute) { continue; } @@ -60,8 +60,9 @@ static void copy_attributes(const Map &attributes } const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); - OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only( - attribute_id, attribute.domain, data_type); + GSpanAttributeWriter result_attribute = + result_component.attributes_for_write()->lookup_or_add_for_write_only_span( + attribute_id, attribute.domain, data_type); if (!result_attribute) { continue; @@ -70,10 +71,10 @@ static void copy_attributes(const Map &attributes attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); VArraySpan span{attribute.varray.typed()}; - MutableSpan out_span = result_attribute.as_span(); + MutableSpan out_span = result_attribute.span.typed(); out_span.copy_from(span); }); - result_attribute.save(); + result_attribute.finish(); } } @@ -89,7 +90,7 @@ static void copy_attributes_based_on_mask(const Map::Item entry : attributes.items()) { const AttributeIDRef attribute_id = entry.key; - ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(attribute_id); + GAttributeReader attribute = in_component.attributes()->lookup(attribute_id); if (!attribute) { continue; } @@ -100,8 +101,9 @@ static void copy_attributes_based_on_mask(const Maplookup_or_add_for_write_only_span( + attribute_id, attribute.domain, data_type); if (!result_attribute) { continue; @@ -110,10 +112,10 @@ static void copy_attributes_based_on_mask(const Map span{attribute.varray.typed()}; - MutableSpan out_span = result_attribute.as_span(); + MutableSpan out_span = result_attribute.span.typed(); copy_data_based_on_mask(span, out_span, mask); }); - result_attribute.save(); + result_attribute.finish(); } } @@ -125,7 +127,7 @@ static void copy_attributes_based_on_map(const Map::Item entry : attributes.items()) { const AttributeIDRef attribute_id = entry.key; - ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(attribute_id); + GAttributeReader attribute = in_component.attributes()->lookup(attribute_id); if (!attribute) { continue; } @@ -136,8 +138,9 @@ static void copy_attributes_based_on_map(const Maplookup_or_add_for_write_only_span( + attribute_id, attribute.domain, data_type); if (!result_attribute) { continue; @@ -146,10 +149,10 @@ static void copy_attributes_based_on_map(const Map span{attribute.varray.typed()}; - MutableSpan out_span = result_attribute.as_span(); + MutableSpan out_span = result_attribute.span.typed(); copy_data_based_on_map(span, out_span, index_map); }); - result_attribute.save(); + result_attribute.finish(); } } @@ -319,7 +322,7 @@ static void delete_curves_selection(GeometrySet &geometry_set, const CurveComponent &src_component = *geometry_set.get_component_for_read(); GeometryComponentFieldContext field_context{src_component, selection_domain}; - const int domain_num = src_component.attribute_domain_num(selection_domain); + const int domain_num = src_component.attribute_domain_size(selection_domain); fn::FieldEvaluator evaluator{field_context, domain_num}; evaluator.set_selection(selection_field); evaluator.evaluate(); @@ -351,7 +354,7 @@ static void separate_point_cloud_selection(GeometrySet &geometry_set, *geometry_set.get_component_for_read(); GeometryComponentFieldContext field_context{src_points, ATTR_DOMAIN_POINT}; - fn::FieldEvaluator evaluator{field_context, src_points.attribute_domain_num(ATTR_DOMAIN_POINT)}; + fn::FieldEvaluator evaluator{field_context, src_points.attribute_domain_size(ATTR_DOMAIN_POINT)}; evaluator.set_selection(selection_field); evaluator.evaluate(); const IndexMask selection = evaluator.get_evaluated_selection_as_mask(); @@ -379,8 +382,7 @@ static void delete_selected_instances(GeometrySet &geometry_set, InstancesComponent &instances = geometry_set.get_component_for_write(); GeometryComponentFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE}; - fn::FieldEvaluator evaluator{field_context, - instances.attribute_domain_num(ATTR_DOMAIN_INSTANCE)}; + fn::FieldEvaluator evaluator{field_context, instances.instances_num()}; evaluator.set_selection(selection_field); evaluator.evaluate(); const IndexMask selection = evaluator.get_evaluated_selection_as_mask(); @@ -1058,7 +1060,7 @@ static void separate_mesh_selection(GeometrySet &geometry_set, GeometryComponentFieldContext field_context{src_component, selection_domain}; fn::FieldEvaluator evaluator{field_context, - src_component.attribute_domain_num(selection_domain)}; + src_component.attribute_domain_size(selection_domain)}; evaluator.add(selection_field); evaluator.evaluate(); const VArray selection = evaluator.get_evaluated(0); diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc index f95601813a3..faf5b7f65fa 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc @@ -290,31 +290,32 @@ BLI_NOINLINE static void propagate_existing_attributes( const Span looptri_indices) { const Mesh &mesh = *mesh_component.get_for_read(); + const AttributeAccessor mesh_attributes = *mesh_component.attributes(); + MutableAttributeAccessor point_attributes = *point_component.attributes_for_write(); for (Map::Item entry : attributes.items()) { const AttributeIDRef attribute_id = entry.key; const eCustomDataType output_data_type = entry.value.data_type; - ReadAttributeLookup source_attribute = mesh_component.attribute_try_get_for_read(attribute_id); + GAttributeReader source_attribute = mesh_attributes.lookup(attribute_id); if (!source_attribute) { continue; } /* The output domain is always #ATTR_DOMAIN_POINT, since we are creating a point cloud. */ - OutputAttribute attribute_out = point_component.attribute_try_get_for_output_only( + GSpanAttributeWriter attribute_out = point_attributes.lookup_or_add_for_write_only_span( attribute_id, ATTR_DOMAIN_POINT, output_data_type); if (!attribute_out) { continue; } - GMutableSpan out_span = attribute_out.as_span(); interpolate_attribute(mesh, bary_coords, looptri_indices, source_attribute.domain, source_attribute.varray, - out_span); - attribute_out.save(); + attribute_out.span); + attribute_out.finish(); } } @@ -331,25 +332,21 @@ BLI_NOINLINE static void compute_attribute_outputs(const MeshComponent &mesh_com const Span looptri_indices, const AttributeOutputs &attribute_outputs) { - OutputAttribute_Typed id_attribute = point_component.attribute_try_get_for_output_only( - "id", ATTR_DOMAIN_POINT); - MutableSpan ids = id_attribute.as_span(); + MutableAttributeAccessor pointcloud_attributes = *point_component.attributes_for_write(); - OutputAttribute_Typed normal_attribute; - OutputAttribute_Typed rotation_attribute; + SpanAttributeWriter ids = pointcloud_attributes.lookup_or_add_for_write_only_span( + "id", ATTR_DOMAIN_POINT); - MutableSpan normals; - MutableSpan rotations; + SpanAttributeWriter normals; + SpanAttributeWriter rotations; if (attribute_outputs.normal_id) { - normal_attribute = point_component.attribute_try_get_for_output_only( + normals = pointcloud_attributes.lookup_or_add_for_write_only_span( attribute_outputs.normal_id.get(), ATTR_DOMAIN_POINT); - normals = normal_attribute.as_span(); } if (attribute_outputs.rotation_id) { - rotation_attribute = point_component.attribute_try_get_for_output_only( + rotations = pointcloud_attributes.lookup_or_add_for_write_only_span( attribute_outputs.rotation_id.get(), ATTR_DOMAIN_POINT); - rotations = rotation_attribute.as_span(); } const Mesh &mesh = *mesh_component.get_for_read(); @@ -368,27 +365,27 @@ BLI_NOINLINE static void compute_attribute_outputs(const MeshComponent &mesh_com const float3 v1_pos = float3(mesh.mvert[v1_index].co); const float3 v2_pos = float3(mesh.mvert[v2_index].co); - ids[i] = noise::hash(noise::hash_float(bary_coord), looptri_index); + ids.span[i] = noise::hash(noise::hash_float(bary_coord), looptri_index); float3 normal; - if (!normals.is_empty() || !rotations.is_empty()) { + if (!normals.span.is_empty() || !rotations.span.is_empty()) { normal_tri_v3(normal, v0_pos, v1_pos, v2_pos); } - if (!normals.is_empty()) { - normals[i] = normal; + if (!normals.span.is_empty()) { + normals.span[i] = normal; } - if (!rotations.is_empty()) { - rotations[i] = normal_to_euler_rotation(normal); + if (!rotations.span.is_empty()) { + rotations.span[i] = normal_to_euler_rotation(normal); } } - id_attribute.save(); + ids.finish(); - if (normal_attribute) { - normal_attribute.save(); + if (normals) { + normals.finish(); } - if (rotation_attribute) { - rotation_attribute.save(); + if (rotations) { + rotations.finish(); } } @@ -398,11 +395,11 @@ static Array calc_full_density_factors_with_selection(const MeshComponent { const eAttrDomain attribute_domain = ATTR_DOMAIN_CORNER; GeometryComponentFieldContext field_context{component, attribute_domain}; - const int domain_num = component.attribute_domain_num(attribute_domain); + const int domain_size = component.attribute_domain_size(attribute_domain); - Array densities(domain_num, 0.0f); + Array densities(domain_size, 0.0f); - fn::FieldEvaluator evaluator{field_context, domain_num}; + fn::FieldEvaluator evaluator{field_context, domain_size}; evaluator.set_selection(selection_field); evaluator.add_with_destination(density_field, densities.as_mutable_span()); evaluator.evaluate(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc index 8a256a9b91b..bf5479d552e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc @@ -146,9 +146,12 @@ static void transfer_attributes( const GeometryComponent &src_component, GeometryComponent &dst_component) { + const AttributeAccessor src_attributes = *src_component.attributes(); + MutableAttributeAccessor dst_attributes = *dst_component.attributes_for_write(); + for (Map::Item entry : attributes.items()) { const AttributeIDRef attribute_id = entry.key; - ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read(attribute_id); + GAttributeReader src_attribute = src_attributes.lookup(attribute_id); if (!src_attribute) { continue; } @@ -166,7 +169,7 @@ static void transfer_attributes( } const eCustomDataType data_type = bke::cpp_type_to_custom_data_type( src_attribute.varray.type()); - OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( + GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_only_span( attribute_id, out_domain, data_type); if (!dst_attribute) { @@ -176,7 +179,7 @@ static void transfer_attributes( attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); VArraySpan span{src_attribute.varray.typed()}; - MutableSpan dst_span = dst_attribute.as_span(); + MutableSpan dst_span = dst_attribute.span.typed(); if (src_attribute.domain == ATTR_DOMAIN_FACE) { dst_span.take_front(span.size()).copy_from(span); if (keep_boundaries) { @@ -193,7 +196,7 @@ static void transfer_attributes( copy_data_based_on_new_to_old_map(span, dst_span, new_to_old_face_corners_map); } }); - dst_attribute.save(); + dst_attribute.finish(); } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc index 5fe300e0a08..41136060ab7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc @@ -147,17 +147,17 @@ static void create_duplicate_index_attribute(GeometryComponent &component, const IndexAttributes &attribute_outputs, const Span offsets) { - OutputAttribute_Typed copy_attribute = component.attribute_try_get_for_output_only( - attribute_outputs.duplicate_index.get(), output_domain); - MutableSpan duplicate_indices = copy_attribute.as_span(); + SpanAttributeWriter duplicate_indices = + component.attributes_for_write()->lookup_or_add_for_write_only_span( + attribute_outputs.duplicate_index.get(), output_domain); for (const int i : IndexRange(selection.size())) { const IndexRange range = range_for_offsets_index(offsets, i); - MutableSpan indices = duplicate_indices.slice(range); + MutableSpan indices = duplicate_indices.span.slice(range); for (const int i : indices.index_range()) { indices[i] = i; } } - copy_attribute.save(); + duplicate_indices.finish(); } /** @@ -168,20 +168,21 @@ static void copy_stable_id_point(const Span offsets, const GeometryComponent &src_component, GeometryComponent &dst_component) { - ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id"); + GAttributeReader src_attribute = src_component.attributes()->lookup("id"); if (!src_attribute) { return; } - OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( - "id", ATTR_DOMAIN_POINT, CD_PROP_INT32); + GSpanAttributeWriter dst_attribute = + dst_component.attributes_for_write()->lookup_or_add_for_write_only_span( + "id", ATTR_DOMAIN_POINT, CD_PROP_INT32); if (!dst_attribute) { return; } VArraySpan src{src_attribute.varray.typed()}; - MutableSpan dst = dst_attribute.as_span(); + MutableSpan dst = dst_attribute.span.typed(); threaded_id_offset_copy(offsets, src, dst); - dst_attribute.save(); + dst_attribute.finish(); } static void copy_attributes_without_id(GeometrySet &geometry_set, @@ -197,25 +198,26 @@ static void copy_attributes_without_id(GeometrySet &geometry_set, for (const Map::Item entry : attributes.items()) { const AttributeIDRef attribute_id = entry.key; - ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read(attribute_id); + GAttributeReader src_attribute = src_component.attributes()->lookup(attribute_id); if (!src_attribute || src_attribute.domain != domain) { continue; } eAttrDomain out_domain = src_attribute.domain; const eCustomDataType data_type = bke::cpp_type_to_custom_data_type( src_attribute.varray.type()); - OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( - attribute_id, out_domain, data_type); + GSpanAttributeWriter dst_attribute = + dst_component.attributes_for_write()->lookup_or_add_for_write_only_span( + attribute_id, out_domain, data_type); if (!dst_attribute) { continue; } attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); VArraySpan src = src_attribute.varray.typed(); - MutableSpan dst = dst_attribute.as_span(); + MutableSpan dst = dst_attribute.span.typed(); threaded_slice_fill(offsets, selection, src, dst); }); - dst_attribute.save(); + dst_attribute.finish(); } } @@ -242,7 +244,7 @@ static void copy_curve_attributes_without_id(const GeometrySet &geometry_set, for (const Map::Item entry : attributes.items()) { const AttributeIDRef attribute_id = entry.key; - ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read(attribute_id); + GAttributeReader src_attribute = src_component.attributes()->lookup(attribute_id); if (!src_attribute) { continue; } @@ -250,8 +252,9 @@ static void copy_curve_attributes_without_id(const GeometrySet &geometry_set, eAttrDomain out_domain = src_attribute.domain; const eCustomDataType data_type = bke::cpp_type_to_custom_data_type( src_attribute.varray.type()); - OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( - attribute_id, out_domain, data_type); + GSpanAttributeWriter dst_attribute = + dst_component.attributes_for_write()->lookup_or_add_for_write_only_span( + attribute_id, out_domain, data_type); if (!dst_attribute) { continue; } @@ -259,7 +262,7 @@ static void copy_curve_attributes_without_id(const GeometrySet &geometry_set, attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); VArraySpan src{src_attribute.varray.typed()}; - MutableSpan dst = dst_attribute.as_span(); + MutableSpan dst = dst_attribute.span.typed(); switch (out_domain) { case ATTR_DOMAIN_CURVE: @@ -280,7 +283,7 @@ static void copy_curve_attributes_without_id(const GeometrySet &geometry_set, break; } }); - dst_attribute.save(); + dst_attribute.finish(); } } @@ -297,18 +300,19 @@ static void copy_stable_id_curves(const bke::CurvesGeometry &src_curves, bke::CurvesGeometry &dst_curves, CurveComponent &dst_component) { - ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id"); + GAttributeReader src_attribute = src_component.attributes()->lookup("id"); if (!src_attribute) { return; } - OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( - "id", ATTR_DOMAIN_POINT, CD_PROP_INT32); + GSpanAttributeWriter dst_attribute = + dst_component.attributes_for_write()->lookup_or_add_for_write_only_span( + "id", ATTR_DOMAIN_POINT, CD_PROP_INT32); if (!dst_attribute) { return; } VArraySpan src{src_attribute.varray.typed()}; - MutableSpan dst = dst_attribute.as_span(); + MutableSpan dst = dst_attribute.span.typed(); threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) { for (const int i_selection : range) { @@ -322,7 +326,7 @@ static void copy_stable_id_curves(const bke::CurvesGeometry &src_curves, } } }); - dst_attribute.save(); + dst_attribute.finish(); } static void duplicate_curves(GeometrySet &geometry_set, @@ -423,7 +427,7 @@ static void copy_face_attributes_without_id(GeometrySet &geometry_set, for (const Map::Item entry : attributes.items()) { const AttributeIDRef attribute_id = entry.key; - ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read(attribute_id); + GAttributeReader src_attribute = src_component.attributes()->lookup(attribute_id); if (!src_attribute) { continue; } @@ -431,8 +435,9 @@ static void copy_face_attributes_without_id(GeometrySet &geometry_set, eAttrDomain out_domain = src_attribute.domain; const eCustomDataType data_type = bke::cpp_type_to_custom_data_type( src_attribute.varray.type()); - OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( - attribute_id, out_domain, data_type); + GSpanAttributeWriter dst_attribute = + dst_component.attributes_for_write()->lookup_or_add_for_write_only_span( + attribute_id, out_domain, data_type); if (!dst_attribute) { continue; } @@ -440,7 +445,7 @@ static void copy_face_attributes_without_id(GeometrySet &geometry_set, attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); VArraySpan src{src_attribute.varray.typed()}; - MutableSpan dst = dst_attribute.as_span(); + MutableSpan dst = dst_attribute.span.typed(); switch (out_domain) { case ATTR_DOMAIN_FACE: @@ -459,7 +464,7 @@ static void copy_face_attributes_without_id(GeometrySet &geometry_set, break; } }); - dst_attribute.save(); + dst_attribute.finish(); } } @@ -477,18 +482,19 @@ static void copy_stable_id_faces(const Mesh &mesh, const MeshComponent &src_component, MeshComponent &dst_component) { - ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id"); + GAttributeReader src_attribute = src_component.attributes()->lookup("id"); if (!src_attribute) { return; } - OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( - "id", ATTR_DOMAIN_POINT, CD_PROP_INT32); + GSpanAttributeWriter dst_attribute = + dst_component.attributes_for_write()->lookup_or_add_for_write_only_span( + "id", ATTR_DOMAIN_POINT, CD_PROP_INT32); if (!dst_attribute) { return; } VArraySpan src{src_attribute.varray.typed()}; - MutableSpan dst = dst_attribute.as_span(); + MutableSpan dst = dst_attribute.span.typed(); Span polys(mesh.mpoly, mesh.totpoly); int loop_index = 0; @@ -511,7 +517,7 @@ static void copy_stable_id_faces(const Mesh &mesh, } } - dst_attribute.save(); + dst_attribute.finish(); } static void duplicate_faces(GeometrySet &geometry_set, @@ -636,7 +642,7 @@ static void copy_edge_attributes_without_id(GeometrySet &geometry_set, for (const Map::Item entry : attributes.items()) { const AttributeIDRef attribute_id = entry.key; - ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read(attribute_id); + GAttributeReader src_attribute = src_component.attributes()->lookup(attribute_id); if (!src_attribute) { continue; } @@ -644,15 +650,16 @@ static void copy_edge_attributes_without_id(GeometrySet &geometry_set, const eAttrDomain out_domain = src_attribute.domain; const eCustomDataType data_type = bke::cpp_type_to_custom_data_type( src_attribute.varray.type()); - OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( - attribute_id, out_domain, data_type); + GSpanAttributeWriter dst_attribute = + dst_component.attributes_for_write()->lookup_or_add_for_write_only_span( + attribute_id, out_domain, data_type); if (!dst_attribute) { continue; } attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); VArraySpan src{src_attribute.varray.typed()}; - MutableSpan dst = dst_attribute.as_span(); + MutableSpan dst = dst_attribute.span.typed(); switch (out_domain) { case ATTR_DOMAIN_EDGE: @@ -665,7 +672,7 @@ static void copy_edge_attributes_without_id(GeometrySet &geometry_set, break; } }); - dst_attribute.save(); + dst_attribute.finish(); } } @@ -679,12 +686,13 @@ static void copy_stable_id_edges(const Mesh &mesh, const MeshComponent &src_component, MeshComponent &dst_component) { - ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id"); + GAttributeReader src_attribute = src_component.attributes()->lookup("id"); if (!src_attribute) { return; } - OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( - "id", ATTR_DOMAIN_POINT, CD_PROP_INT32); + GSpanAttributeWriter dst_attribute = + dst_component.attributes_for_write()->lookup_or_add_for_write_only_span( + "id", ATTR_DOMAIN_POINT, CD_PROP_INT32); if (!dst_attribute) { return; } @@ -692,7 +700,7 @@ static void copy_stable_id_edges(const Mesh &mesh, Span edges(mesh.medge, mesh.totedge); VArraySpan src{src_attribute.varray.typed()}; - MutableSpan dst = dst_attribute.as_span(); + MutableSpan dst = dst_attribute.span.typed(); threading::parallel_for(IndexRange(selection.size()), 1024, [&](IndexRange range) { for (const int i_selection : range) { const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_selection); @@ -710,7 +718,7 @@ static void copy_stable_id_edges(const Mesh &mesh, } } }); - dst_attribute.save(); + dst_attribute.finish(); } static void duplicate_edges(GeometrySet &geometry_set, @@ -837,7 +845,7 @@ static void duplicate_points_curve(GeometrySet &geometry_set, for (const Map::Item entry : attributes.items()) { const AttributeIDRef attribute_id = entry.key; - ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read(attribute_id); + GAttributeReader src_attribute = src_component.attributes()->lookup(attribute_id); if (!src_attribute) { continue; } @@ -845,8 +853,9 @@ static void duplicate_points_curve(GeometrySet &geometry_set, eAttrDomain domain = src_attribute.domain; const eCustomDataType data_type = bke::cpp_type_to_custom_data_type( src_attribute.varray.type()); - OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( - attribute_id, domain, data_type); + GSpanAttributeWriter dst_attribute = + dst_component.attributes_for_write()->lookup_or_add_for_write_only_span( + attribute_id, domain, data_type); if (!dst_attribute) { continue; } @@ -854,7 +863,7 @@ static void duplicate_points_curve(GeometrySet &geometry_set, attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); VArraySpan src{src_attribute.varray.typed()}; - MutableSpan dst = dst_attribute.as_span(); + MutableSpan dst = dst_attribute.span.typed(); switch (domain) { case ATTR_DOMAIN_CURVE: @@ -873,7 +882,7 @@ static void duplicate_points_curve(GeometrySet &geometry_set, break; } }); - dst_attribute.save(); + dst_attribute.finish(); } copy_stable_id_point(offsets, src_component, dst_component); @@ -949,7 +958,7 @@ static void duplicate_points_pointcloud(GeometrySet &geometry_set, { const PointCloudComponent &src_points = *geometry_set.get_component_for_read(); - const int point_num = src_points.attribute_domain_num(ATTR_DOMAIN_POINT); + const int point_num = src_points.attribute_domain_size(ATTR_DOMAIN_POINT); GeometryComponentFieldContext field_context{src_points, ATTR_DOMAIN_POINT}; FieldEvaluator evaluator{field_context, point_num}; diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc index 94fbec66bfe..84acab47661 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc @@ -57,8 +57,8 @@ static void node_geo_exec(GeoNodeExecParams params) const MeshComponent &mesh_component = *geometry_set.get_component_for_read(); GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_EDGE}; - const int domain_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_EDGE); - fn::FieldEvaluator selection_evaluator{field_context, domain_num}; + const int domain_size = mesh_component.attribute_domain_size(ATTR_DOMAIN_EDGE); + fn::FieldEvaluator selection_evaluator{field_context, domain_size}; selection_evaluator.add(selection_field); selection_evaluator.evaluate(); const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0); diff --git a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc index 59d7154db6e..baa9952b950 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc @@ -66,21 +66,21 @@ static void save_selection_as_attribute(MeshComponent &component, const eAttrDomain domain, const IndexMask selection) { - BLI_assert(!component.attribute_exists(id)); + BLI_assert(!component.attributes()->contains(id)); - OutputAttribute_Typed attribute = component.attribute_try_get_for_output_only( - id, domain); + SpanAttributeWriter attribute = + component.attributes_for_write()->lookup_or_add_for_write_span(id, domain); /* Rely on the new attribute being zeroed by default. */ - BLI_assert(!attribute.as_span().as_span().contains(true)); + BLI_assert(!attribute.span.as_span().contains(true)); if (selection.is_range()) { - attribute.as_span().slice(selection.as_range()).fill(true); + attribute.span.slice(selection.as_range()).fill(true); } else { - attribute.as_span().fill_indices(selection, true); + attribute.span.fill_indices(selection, true); } - attribute.save(); + attribute.finish(); } static MutableSpan mesh_verts(Mesh &mesh) @@ -168,7 +168,7 @@ static MutableSpan get_orig_index_layer(Mesh &mesh, const eAttrDomain domai component.replace(&mesh, GeometryOwnershipType::ReadOnly); CustomData &custom_data = get_customdata(mesh, domain); if (int *orig_indices = static_cast(CustomData_get_layer(&custom_data, CD_ORIGINDEX))) { - return {orig_indices, component.attribute_domain_num(domain)}; + return {orig_indices, component.attribute_domain_size(domain)}; } return {}; } @@ -280,16 +280,18 @@ static void extrude_mesh_vertices(MeshComponent &component, new_edges[i_selection] = new_loose_edge(selection[i_selection], new_vert_range[i_selection]); } - component.attribute_foreach([&](const AttributeIDRef &id, const AttributeMetaData meta_data) { + MutableAttributeAccessor attributes = *component.attributes_for_write(); + + attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) { if (!ELEM(meta_data.domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE)) { return true; } - OutputAttribute attribute = component.attribute_try_get_for_output( + GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span( id, meta_data.domain, meta_data.data_type); attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) { using T = decltype(dummy); - MutableSpan data = attribute.as_span().typed(); - switch (attribute.domain()) { + MutableSpan data = attribute.span.typed(); + switch (attribute.domain) { case ATTR_DOMAIN_POINT: { /* New vertices copy the attribute values from their source vertex. */ copy_with_mask(data.slice(new_vert_range), data.as_span(), selection); @@ -307,7 +309,7 @@ static void extrude_mesh_vertices(MeshComponent &component, } }); - attribute.save(); + attribute.finish(); return true; }); @@ -524,8 +526,10 @@ static void extrude_mesh_edges(MeshComponent &component, const Array> new_vert_to_duplicate_edge_map = create_vert_to_edge_map( new_vert_range.size(), duplicate_edges, orig_vert_size); - component.attribute_foreach([&](const AttributeIDRef &id, const AttributeMetaData meta_data) { - OutputAttribute attribute = component.attribute_try_get_for_output( + MutableAttributeAccessor attributes = *component.attributes_for_write(); + + attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) { + GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span( id, meta_data.domain, meta_data.data_type); if (!attribute) { return true; /* Impossible to write the "normal" attribute. */ @@ -533,8 +537,8 @@ static void extrude_mesh_edges(MeshComponent &component, attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) { using T = decltype(dummy); - MutableSpan data = attribute.as_span().typed(); - switch (attribute.domain()) { + MutableSpan data = attribute.span.typed(); + switch (attribute.domain) { case ATTR_DOMAIN_POINT: { /* New vertices copy the attribute values from their source vertex. */ copy_with_indices(data.slice(new_vert_range), data.as_span(), new_vert_indices); @@ -626,7 +630,7 @@ static void extrude_mesh_edges(MeshComponent &component, } }); - attribute.save(); + attribute.finish(); return true; }); @@ -902,8 +906,10 @@ static void extrude_mesh_face_regions(MeshComponent &component, const Array> new_vert_to_duplicate_edge_map = create_vert_to_edge_map( new_vert_range.size(), boundary_edges, orig_vert_size); - component.attribute_foreach([&](const AttributeIDRef &id, const AttributeMetaData meta_data) { - OutputAttribute attribute = component.attribute_try_get_for_output( + MutableAttributeAccessor attributes = *component.attributes_for_write(); + + attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) { + GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span( id, meta_data.domain, meta_data.data_type); if (!attribute) { return true; /* Impossible to write the "normal" attribute. */ @@ -911,8 +917,8 @@ static void extrude_mesh_face_regions(MeshComponent &component, attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) { using T = decltype(dummy); - MutableSpan data = attribute.as_span().typed(); - switch (attribute.domain()) { + MutableSpan data = attribute.span.typed(); + switch (attribute.domain) { case ATTR_DOMAIN_POINT: { /* New vertices copy the attributes from their original vertices. */ copy_with_indices(data.slice(new_vert_range), data.as_span(), new_vert_indices); @@ -991,7 +997,7 @@ static void extrude_mesh_face_regions(MeshComponent &component, } }); - attribute.save(); + attribute.finish(); return true; }); @@ -1154,8 +1160,10 @@ static void extrude_individual_mesh_faces(MeshComponent &component, } }); - component.attribute_foreach([&](const AttributeIDRef &id, const AttributeMetaData meta_data) { - OutputAttribute attribute = component.attribute_try_get_for_output( + MutableAttributeAccessor attributes = *component.attributes_for_write(); + + attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) { + GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span( id, meta_data.domain, meta_data.data_type); if (!attribute) { return true; /* Impossible to write the "normal" attribute. */ @@ -1163,8 +1171,8 @@ static void extrude_individual_mesh_faces(MeshComponent &component, attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) { using T = decltype(dummy); - MutableSpan data = attribute.as_span().typed(); - switch (attribute.domain()) { + MutableSpan data = attribute.span.typed(); + switch (attribute.domain) { case ATTR_DOMAIN_POINT: { /* New vertices copy the attributes from their original vertices. */ MutableSpan new_data = data.slice(new_vert_range); @@ -1267,7 +1275,7 @@ static void extrude_individual_mesh_faces(MeshComponent &component, } }); - attribute.save(); + attribute.finish(); return true; }); diff --git a/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc b/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc index 7839e148ee3..64861e529bc 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc @@ -91,7 +91,7 @@ class FieldAtIndex final : public GeometryFieldInput { { const GeometryComponentFieldContext value_field_context{component, value_field_domain_}; FieldEvaluator value_evaluator{value_field_context, - component.attribute_domain_num(value_field_domain_)}; + component.attribute_domain_size(value_field_domain_)}; value_evaluator.add(value_field_); value_evaluator.evaluate(); const GVArray &values = value_evaluator.get_evaluated(0); diff --git a/source/blender/nodes/geometry/nodes/node_geo_field_on_domain.cc b/source/blender/nodes/geometry/nodes/node_geo_field_on_domain.cc index e6906f4fb21..5939ed5334d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_field_on_domain.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_field_on_domain.cc @@ -85,12 +85,12 @@ class FieldOnDomain final : public GeometryFieldInput { IndexMask /* mask */) const final { const GeometryComponentFieldContext context{component, src_domain_}; - FieldEvaluator value_evaluator{context, component.attribute_domain_num(src_domain_)}; + FieldEvaluator value_evaluator{context, component.attribute_domain_size(src_domain_)}; value_evaluator.add(src_field_); value_evaluator.evaluate(); const GVArray &values = value_evaluator.get_evaluated(0); - return component.attribute_try_adapt_domain(values, src_domain_, domain); + return component.attributes()->adapt_domain(values, src_domain_, domain); } }; diff --git a/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc index 0484017cf3b..15b2822805a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc @@ -22,11 +22,11 @@ static void node_declare(NodeDeclarationBuilder &b) static void mesh_flip_faces(MeshComponent &component, const Field &selection_field) { GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE}; - const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_FACE); - if (domain_num == 0) { + const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE); + if (domain_size == 0) { return; } - fn::FieldEvaluator evaluator{field_context, domain_num}; + fn::FieldEvaluator evaluator{field_context, domain_size}; evaluator.add(selection_field); evaluator.evaluate(); const IndexMask selection = evaluator.get_evaluated_as_mask(0); @@ -49,20 +49,21 @@ static void mesh_flip_faces(MeshComponent &component, const Field &selecti } } - component.attribute_foreach( + MutableAttributeAccessor attributes = *component.attributes_for_write(); + attributes.for_all( [&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { if (meta_data.domain == ATTR_DOMAIN_CORNER) { - OutputAttribute attribute = component.attribute_try_get_for_output( - attribute_id, ATTR_DOMAIN_CORNER, meta_data.data_type, nullptr); + GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span( + attribute_id, ATTR_DOMAIN_CORNER, meta_data.data_type); attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) { using T = decltype(dummy); - MutableSpan dst_span = attribute.as_span(); + MutableSpan dst_span = attribute.span.typed(); for (const int j : selection.index_range()) { const MPoly &poly = polys[selection[j]]; dst_span.slice(poly.loopstart + 1, poly.totloop - 1).reverse(); } }); - attribute.save(); + attribute.finish(); } return true; }); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc index e0aaf43235c..bc1b9e940a1 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc @@ -39,11 +39,13 @@ class HandlePositionFieldInput final : public GeometryFieldInput { evaluator.evaluate(); const VArray relative = evaluator.get_evaluated(0); - VArray positions = component.attribute_get_for_read( + const AttributeAccessor attributes = *component.attributes(); + + VArray positions = attributes.lookup_or_default( "position", ATTR_DOMAIN_POINT, {0, 0, 0}); StringRef side = left_ ? "handle_left" : "handle_right"; - VArray handles = component.attribute_get_for_read( + VArray handles = attributes.lookup_or_default( side, ATTR_DOMAIN_POINT, {0, 0, 0}); if (relative.is_single()) { @@ -52,10 +54,10 @@ class HandlePositionFieldInput final : public GeometryFieldInput { for (const int i : positions.index_range()) { output[i] = handles[i] - positions[i]; } - return component.attribute_try_adapt_domain( + return attributes.adapt_domain( VArray::ForContainer(std::move(output)), ATTR_DOMAIN_POINT, domain); } - return component.attribute_try_adapt_domain(handles, ATTR_DOMAIN_POINT, domain); + return attributes.adapt_domain(handles, ATTR_DOMAIN_POINT, domain); } Array output(positions.size()); @@ -67,7 +69,7 @@ class HandlePositionFieldInput final : public GeometryFieldInput { output[i] = handles[i]; } } - return component.attribute_try_adapt_domain( + return component.attributes()->adapt_domain( VArray::ForContainer(std::move(output)), ATTR_DOMAIN_POINT, domain); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc index f27e0305c7d..b009aaa5291 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc @@ -91,7 +91,7 @@ class AngleFieldInput final : public GeometryFieldInput { }; VArray angles = VArray::ForFunc(mesh->totedge, angle_fn); - return component.attribute_try_adapt_domain( + return component.attributes()->adapt_domain( std::move(angles), ATTR_DOMAIN_EDGE, domain); } @@ -166,7 +166,7 @@ class SignedAngleFieldInput final : public GeometryFieldInput { }; VArray angles = VArray::ForFunc(mesh->totedge, angle_fn); - return component.attribute_try_adapt_domain( + return component.attributes()->adapt_domain( std::move(angles), ATTR_DOMAIN_EDGE, domain); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc index cbc2ebc3e68..50d6998bb27 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc @@ -40,7 +40,7 @@ class EdgeNeighborCountFieldInput final : public GeometryFieldInput { face_count[mesh->mloop[i].e]++; } - return mesh_component.attribute_try_adapt_domain( + return mesh_component.attributes()->adapt_domain( VArray::ForContainer(std::move(face_count)), ATTR_DOMAIN_EDGE, domain); } return {}; diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc index 6201ad26bfb..83e511f45c2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc @@ -93,14 +93,14 @@ static VArray construct_edge_positions_gvarray(const MeshComponent &comp } if (vertex == VERTEX_ONE) { - return component.attribute_try_adapt_domain( + return component.attributes()->adapt_domain( VArray::ForFunc( mesh->totedge, [mesh](const int i) { return float3(mesh->mvert[mesh->medge[i].v1].co); }), ATTR_DOMAIN_EDGE, domain); } - return component.attribute_try_adapt_domain( + return component.attributes()->adapt_domain( VArray::ForFunc( mesh->totedge, [mesh](const int i) { return float3(mesh->mvert[mesh->medge[i].v2].co); }), diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc index 7a0e3e37a65..4d21bf9443a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc @@ -29,7 +29,7 @@ static VArray construct_face_area_gvarray(const MeshComponent &component, return BKE_mesh_calc_poly_area(mp, &mesh->mloop[mp->loopstart], mesh->mvert); }; - return component.attribute_try_adapt_domain( + return component.attributes()->adapt_domain( VArray::ForFunc(mesh->totpoly, area_fn), ATTR_DOMAIN_FACE, domain); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc index d02f7291704..6b04ff08d9e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc @@ -80,7 +80,7 @@ class PlanarFieldInput final : public GeometryFieldInput { return max - min < thresholds[i_poly] / 2.0f; }; - return component.attribute_try_adapt_domain( + return component.attributes()->adapt_domain( VArray::ForFunc(mesh->totpoly, planar_fn), ATTR_DOMAIN_FACE, domain); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc index 67a21cb06f0..a225ce61b14 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc @@ -40,7 +40,7 @@ static VArray construct_neighbor_count_gvarray(const MeshComponent &compone } } - return component.attribute_try_adapt_domain( + return component.attributes()->adapt_domain( VArray::ForContainer(std::move(poly_count)), ATTR_DOMAIN_FACE, domain); } @@ -83,7 +83,7 @@ static VArray construct_vertex_count_gvarray(const MeshComponent &component return {}; } - return component.attribute_try_adapt_domain( + return component.attributes()->adapt_domain( VArray::ForFunc(mesh->totpoly, [mesh](const int i) -> float { return mesh->mpoly[i].totloop; }), ATTR_DOMAIN_FACE, diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc index bd57924d685..2c7eef5665f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc @@ -54,7 +54,7 @@ class IslandFieldInput final : public GeometryFieldInput { output[i] = ordered_roots.index_of_or_add(root); } - return mesh_component.attribute_try_adapt_domain( + return mesh_component.attributes()->adapt_domain( VArray::ForContainer(std::move(output)), ATTR_DOMAIN_POINT, domain); } @@ -101,7 +101,8 @@ class IslandCountFieldInput final : public GeometryFieldInput { island_list.add(root); } - return VArray::ForSingle(island_list.size(), mesh_component.attribute_domain_num(domain)); + return VArray::ForSingle(island_list.size(), + mesh_component.attribute_domain_size(domain)); } uint64_t hash() const override diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc index def82eefca5..267ba44cc00 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc @@ -32,7 +32,7 @@ static VArray construct_curve_point_count_gvarray(const CurveComponent &com } if (domain == ATTR_DOMAIN_POINT) { VArray count = VArray::ForFunc(curves.curves_num(), count_fn); - return component.attribute_try_adapt_domain( + return component.attributes()->adapt_domain( std::move(count), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc index f5831941094..a2aab5464aa 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc @@ -75,7 +75,7 @@ static VArray construct_curve_tangent_gvarray(const CurveComponent &comp const VArray types = curves.curve_types(); if (curves.is_single_type(CURVE_TYPE_POLY)) { - return component.attribute_try_adapt_domain( + return component.attributes()->adapt_domain( VArray::ForSpan(curves.evaluated_tangents()), ATTR_DOMAIN_POINT, domain); } @@ -86,7 +86,7 @@ static VArray construct_curve_tangent_gvarray(const CurveComponent &comp } if (domain == ATTR_DOMAIN_CURVE) { - return component.attribute_try_adapt_domain( + return component.attributes()->adapt_domain( VArray::ForContainer(std::move(tangents)), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc index 21ef8765e43..3ce26a086e2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc @@ -50,7 +50,7 @@ static void add_instances_from_component( const Map &attributes_to_propagate) { const eAttrDomain domain = ATTR_DOMAIN_POINT; - const int domain_num = src_component.attribute_domain_num(domain); + const int domain_num = src_component.attribute_domain_size(domain); VArray pick_instance; VArray indices; @@ -82,7 +82,7 @@ static void add_instances_from_component( MutableSpan dst_transforms = dst_component.instance_transforms().slice(start_len, select_len); - VArray positions = src_component.attribute_get_for_read( + VArray positions = src_component.attributes()->lookup_or_default( "position", domain, {0, 0, 0}); const InstancesComponent *src_instances = instance.get_component_for_read(); @@ -154,12 +154,12 @@ static void add_instances_from_component( } } - bke::CustomDataAttributes &instance_attributes = dst_component.attributes(); + bke::CustomDataAttributes &instance_attributes = dst_component.instance_attributes(); for (const auto item : attributes_to_propagate.items()) { const AttributeIDRef &attribute_id = item.key; const AttributeKind attribute_kind = item.value; - const GVArray src_attribute = src_component.attribute_get_for_read( + const GVArray src_attribute = src_component.attributes()->lookup_or_default( attribute_id, ATTR_DOMAIN_POINT, attribute_kind.data_type); BLI_assert(src_attribute); std::optional dst_attribute_opt = instance_attributes.get_for_write( diff --git a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc index ffc6137cf83..edbe6e1593f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc @@ -40,9 +40,9 @@ static void convert_instances_to_points(GeometrySet &geometry_set, const InstancesComponent &instances = *geometry_set.get_component_for_read(); GeometryComponentFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE}; - const int domain_num = instances.attribute_domain_num(ATTR_DOMAIN_INSTANCE); + const int domain_size = instances.instances_num(); - fn::FieldEvaluator evaluator{field_context, domain_num}; + fn::FieldEvaluator evaluator{field_context, domain_size}; evaluator.set_selection(std::move(selection_field)); evaluator.add(std::move(position_field)); evaluator.add(std::move(radius_field)); @@ -75,18 +75,18 @@ static void convert_instances_to_points(GeometrySet &geometry_set, const AttributeIDRef &attribute_id = item.key; const AttributeKind attribute_kind = item.value; - const GVArray src = instances.attribute_get_for_read( + const GVArray src = instances.attributes()->lookup_or_default( attribute_id, ATTR_DOMAIN_INSTANCE, attribute_kind.data_type); BLI_assert(src); - OutputAttribute dst = points.attribute_try_get_for_output_only( + GSpanAttributeWriter dst = points.attributes_for_write()->lookup_or_add_for_write_only_span( attribute_id, ATTR_DOMAIN_POINT, attribute_kind.data_type); BLI_assert(dst); attribute_math::convert_to_static_type(attribute_kind.data_type, [&](auto dummy) { using T = decltype(dummy); - copy_attribute_to_points(src.typed(), selection, dst.as_span().typed()); + copy_attribute_to_points(src.typed(), selection, dst.span.typed()); }); - dst.save(); + dst.finish(); } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc index 62cd1d8ac3a..083a505539a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc @@ -24,7 +24,7 @@ static Map get_final_attribute_info( Map info; for (const GeometryComponent *component : components) { - component->attribute_foreach( + component->attributes()->for_all( [&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { if (attribute_id.is_named() && ignored_attributes.contains(attribute_id.name())) { return true; @@ -56,11 +56,11 @@ static void fill_new_attribute(Span src_components, int offset = 0; for (const GeometryComponent *component : src_components) { - const int domain_num = component->attribute_domain_num(domain); + const int domain_num = component->attribute_domain_size(domain); if (domain_num == 0) { continue; } - GVArray read_attribute = component->attribute_get_for_read( + GVArray read_attribute = component->attributes()->lookup_or_default( attribute_id, domain, data_type, nullptr); GVArraySpan src_span{read_attribute}; @@ -83,15 +83,15 @@ static void join_attributes(Span src_components, const AttributeIDRef attribute_id = item.key; const AttributeMetaData &meta_data = item.value; - OutputAttribute write_attribute = result.attribute_try_get_for_output_only( - attribute_id, meta_data.domain, meta_data.data_type); + GSpanAttributeWriter write_attribute = + result.attributes_for_write()->lookup_or_add_for_write_only_span( + attribute_id, meta_data.domain, meta_data.data_type); if (!write_attribute) { continue; } - GMutableSpan dst_span = write_attribute.as_span(); fill_new_attribute( - src_components, attribute_id, meta_data.data_type, meta_data.domain, dst_span); - write_attribute.save(); + src_components, attribute_id, meta_data.data_type, meta_data.domain, write_attribute.span); + write_attribute.finish(); } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc index 5875606da97..ca613ae009b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc @@ -71,7 +71,7 @@ class MaterialSelectionFieldInput final : public GeometryFieldInput { Array selection(mesh->totpoly); select_mesh_by_material(*mesh, material_, IndexMask(mesh->totpoly), selection); - return mesh_component.attribute_try_adapt_domain( + return mesh_component.attributes()->adapt_domain( VArray::ForContainer(std::move(selection)), ATTR_DOMAIN_FACE, domain); return nullptr; diff --git a/source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc b/source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc index 1def4089115..4bc84a7a08a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc @@ -39,7 +39,7 @@ static PointCloud *pointcloud_merge_by_distance(const PointCloudComponent &src_p const float merge_distance, const Field &selection_field) { - const int src_num = src_points.attribute_domain_num(ATTR_DOMAIN_POINT); + const int src_num = src_points.attribute_domain_size(ATTR_DOMAIN_POINT); GeometryComponentFieldContext context{src_points, ATTR_DOMAIN_POINT}; FieldEvaluator evaluator{context, src_num}; evaluator.add(selection_field); @@ -57,7 +57,7 @@ static std::optional mesh_merge_by_distance_connected(const MeshComponen const float merge_distance, const Field &selection_field) { - const int src_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_POINT); + const int src_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT); Array selection(src_num); GeometryComponentFieldContext context{mesh_component, ATTR_DOMAIN_POINT}; FieldEvaluator evaluator{context, src_num}; @@ -72,7 +72,7 @@ static std::optional mesh_merge_by_distance_all(const MeshComponent &mes const float merge_distance, const Field &selection_field) { - const int src_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_POINT); + const int src_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT); GeometryComponentFieldContext context{mesh_component, ATTR_DOMAIN_POINT}; FieldEvaluator evaluator{context, src_num}; evaluator.add(selection_field); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc index b882d4bdf09..cb79ef93de9 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc @@ -480,53 +480,49 @@ static void calculate_selection_outputs(Mesh *mesh, const ConeConfig &config, ConeAttributeOutputs &attribute_outputs) { - MeshComponent mesh_component; - mesh_component.replace(mesh, GeometryOwnershipType::Editable); + MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh); /* Populate "Top" selection output. */ if (attribute_outputs.top_id) { const bool face = !config.top_is_point && config.fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE; - OutputAttribute_Typed attribute = mesh_component.attribute_try_get_for_output_only( + SpanAttributeWriter selection = attributes.lookup_or_add_for_write_only_span( attribute_outputs.top_id.get(), face ? ATTR_DOMAIN_FACE : ATTR_DOMAIN_POINT); - MutableSpan selection = attribute.as_span(); if (config.top_is_point) { - selection[config.first_vert] = true; + selection.span[config.first_vert] = true; } else { - selection.slice(0, face ? config.top_faces_len : config.circle_segments).fill(true); + selection.span.slice(0, face ? config.top_faces_len : config.circle_segments).fill(true); } - attribute.save(); + selection.finish(); } /* Populate "Bottom" selection output. */ if (attribute_outputs.bottom_id) { const bool face = !config.bottom_is_point && config.fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE; - OutputAttribute_Typed attribute = mesh_component.attribute_try_get_for_output_only( + SpanAttributeWriter selection = attributes.lookup_or_add_for_write_only_span( attribute_outputs.bottom_id.get(), face ? ATTR_DOMAIN_FACE : ATTR_DOMAIN_POINT); - MutableSpan selection = attribute.as_span(); if (config.bottom_is_point) { - selection[config.last_vert] = true; + selection.span[config.last_vert] = true; } else if (face) { - selection.slice(config.bottom_faces_start, config.bottom_faces_len).fill(true); + selection.span.slice(config.bottom_faces_start, config.bottom_faces_len).fill(true); } else { - selection.slice(config.last_ring_verts_start + 1, config.circle_segments).fill(true); + selection.span.slice(config.last_ring_verts_start + 1, config.circle_segments).fill(true); } - attribute.save(); + selection.finish(); } /* Populate "Side" selection output. */ if (attribute_outputs.side_id) { - OutputAttribute_Typed attribute = mesh_component.attribute_try_get_for_output_only( + SpanAttributeWriter selection = attributes.lookup_or_add_for_write_only_span( attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE); - MutableSpan selection = attribute.as_span(); - selection.slice(config.side_faces_start, config.side_faces_len).fill(true); - attribute.save(); + selection.span.slice(config.side_faces_start, config.side_faces_len).fill(true); + selection.finish(); } } @@ -540,11 +536,11 @@ static void calculate_selection_outputs(Mesh *mesh, */ static void calculate_cone_uvs(Mesh *mesh, const ConeConfig &config) { - MeshComponent mesh_component; - mesh_component.replace(mesh, GeometryOwnershipType::Editable); - OutputAttribute_Typed uv_attribute = - mesh_component.attribute_try_get_for_output_only("uv_map", ATTR_DOMAIN_CORNER); - MutableSpan uvs = uv_attribute.as_span(); + MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh); + + SpanAttributeWriter uv_attribute = attributes.lookup_or_add_for_write_only_span( + "uv_map", ATTR_DOMAIN_CORNER); + MutableSpan uvs = uv_attribute.span; Array circle(config.circle_segments); float angle = 0.0f; @@ -654,7 +650,7 @@ static void calculate_cone_uvs(Mesh *mesh, const ConeConfig &config) } } - uv_attribute.save(); + uv_attribute.finish(); } static Mesh *create_vertex_mesh() diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc index 523dbd5dac2..9baf0b3171e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc @@ -18,23 +18,22 @@ namespace blender::nodes { static void calculate_uvs( Mesh *mesh, Span verts, Span loops, const float size_x, const float size_y) { - MeshComponent mesh_component; - mesh_component.replace(mesh, GeometryOwnershipType::Editable); - OutputAttribute_Typed uv_attribute = - mesh_component.attribute_try_get_for_output_only("uv_map", ATTR_DOMAIN_CORNER); - MutableSpan uvs = uv_attribute.as_span(); + MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh); + + SpanAttributeWriter uv_attribute = attributes.lookup_or_add_for_write_only_span( + "uv_map", ATTR_DOMAIN_CORNER); const float dx = (size_x == 0.0f) ? 0.0f : 1.0f / size_x; const float dy = (size_y == 0.0f) ? 0.0f : 1.0f / size_y; threading::parallel_for(loops.index_range(), 1024, [&](IndexRange range) { for (const int i : range) { const float3 &co = verts[loops[i].v].co; - uvs[i].x = (co.x + size_x * 0.5f) * dx; - uvs[i].y = (co.y + size_y * 0.5f) * dy; + uv_attribute.span[i].x = (co.x + size_x * 0.5f) * dx; + uv_attribute.span[i].y = (co.y + size_y * 0.5f) * dy; } }); - uv_attribute.save(); + uv_attribute.finish(); } Mesh *create_grid_mesh(const int verts_x, diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc index 4e0e5c7c912..f78752387c6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc @@ -220,11 +220,11 @@ static void calculate_sphere_faces(MutableSpan loops, static void calculate_sphere_uvs(Mesh *mesh, const float segments, const float rings) { - MeshComponent mesh_component; - mesh_component.replace(mesh, GeometryOwnershipType::Editable); - OutputAttribute_Typed uv_attribute = - mesh_component.attribute_try_get_for_output_only("uv_map", ATTR_DOMAIN_CORNER); - MutableSpan uvs = uv_attribute.as_span(); + MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh); + + SpanAttributeWriter uv_attribute = attributes.lookup_or_add_for_write_only_span( + "uv_map", ATTR_DOMAIN_CORNER); + MutableSpan uvs = uv_attribute.span; int loop_index = 0; const float dy = 1.0f / rings; @@ -254,7 +254,7 @@ static void calculate_sphere_uvs(Mesh *mesh, const float segments, const float r uvs[loop_index++] = float2(segment / segments, 1.0f - dy); } - uv_attribute.save(); + uv_attribute.finish(); } static Mesh *create_uv_sphere_mesh(const float radius, const int segments, const int rings) diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc index ec6acf55dd8..f6ee3d00dee 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc @@ -25,7 +25,7 @@ static void node_geo_exec(GeoNodeExecParams params) const MeshComponent &component = *geometry_set.get_component_for_read(); GeometryComponentFieldContext context{component, ATTR_DOMAIN_EDGE}; - fn::FieldEvaluator evaluator{context, component.attribute_domain_num(ATTR_DOMAIN_EDGE)}; + fn::FieldEvaluator evaluator{context, component.attribute_domain_size(ATTR_DOMAIN_EDGE)}; evaluator.add(params.get_input>("Selection")); evaluator.evaluate(); const IndexMask selection = evaluator.get_evaluated_as_mask(0); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc index 7463eb01471..8e621d3ed97 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc @@ -66,7 +66,7 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set, return; } GeometryComponentFieldContext field_context{*mesh_component, domain}; - const int domain_num = mesh_component->attribute_domain_num(domain); + const int domain_num = mesh_component->attribute_domain_size(domain); if (domain_num == 0) { geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES}); return; @@ -83,20 +83,20 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set, PointCloud *pointcloud = BKE_pointcloud_new_nomain(selection.size()); geometry_set.replace_pointcloud(pointcloud); - PointCloudComponent &point_component = - geometry_set.get_component_for_write(); + MutableAttributeAccessor pointcloud_attributes = bke::pointcloud_attributes_for_write( + *pointcloud); - OutputAttribute position = point_component.attribute_try_get_for_output_only( + GSpanAttributeWriter position = pointcloud_attributes.lookup_or_add_for_write_only_span( "position", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3); materialize_compressed_to_uninitialized_threaded( - evaluator.get_evaluated(0), selection, position.as_span()); - position.save(); + evaluator.get_evaluated(0), selection, position.span); + position.finish(); - OutputAttribute radius = point_component.attribute_try_get_for_output_only( + GSpanAttributeWriter radius = pointcloud_attributes.lookup_or_add_for_write_only_span( "radius", ATTR_DOMAIN_POINT, CD_PROP_FLOAT); materialize_compressed_to_uninitialized_threaded( - evaluator.get_evaluated(1), selection, radius.as_span()); - radius.save(); + evaluator.get_evaluated(1), selection, radius.span); + radius.finish(); Map attributes; geometry_set.gather_attributes_for_propagation( @@ -106,12 +106,12 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set, for (Map::Item entry : attributes.items()) { const AttributeIDRef attribute_id = entry.key; const eCustomDataType data_type = entry.value.data_type; - GVArray src = mesh_component->attribute_get_for_read(attribute_id, domain, data_type); - OutputAttribute dst = point_component.attribute_try_get_for_output_only( + GVArray src = mesh_component->attributes()->lookup_or_default(attribute_id, domain, data_type); + GSpanAttributeWriter dst = pointcloud_attributes.lookup_or_add_for_write_only_span( attribute_id, ATTR_DOMAIN_POINT, data_type); if (dst && src) { - materialize_compressed_to_uninitialized_threaded(src, selection, dst.as_span()); - dst.save(); + materialize_compressed_to_uninitialized_threaded(src, selection, dst.span); + dst.finish(); } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_points.cc b/source/blender/nodes/geometry/nodes/node_geo_points.cc index da414960e1d..dd32e6714f4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_points.cc @@ -72,19 +72,20 @@ static void node_geo_exec(GeoNodeExecParams params) PointCloud *new_point_cloud = BKE_pointcloud_new_nomain(count); GeometrySet geometry_set = GeometrySet::create_with_pointcloud(new_point_cloud); PointCloudComponent &points = geometry_set.get_component_for_write(); - OutputAttribute_Typed output_position = points.attribute_try_get_for_output_only( + MutableAttributeAccessor attributes = *points.attributes_for_write(); + AttributeWriter output_position = attributes.lookup_or_add_for_write( "position", ATTR_DOMAIN_POINT); - OutputAttribute_Typed output_radii = points.attribute_try_get_for_output_only( + AttributeWriter output_radii = attributes.lookup_or_add_for_write( "radius", ATTR_DOMAIN_POINT); PointsFieldContext context{count}; fn::FieldEvaluator evaluator{context, count}; - evaluator.add_with_destination(position_field, output_position.as_span()); - evaluator.add_with_destination(radius_field, output_radii.as_span()); + evaluator.add_with_destination(position_field, output_position.varray); + evaluator.add_with_destination(radius_field, output_radii.varray); evaluator.evaluate(); - output_position.save(); - output_radii.save(); + output_position.finish(); + output_radii.finish(); params.set_output("Geometry", std::move(geometry_set)); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc index 95ff53b7146..9cc64d4bc44 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc @@ -38,7 +38,7 @@ static void geometry_set_points_to_vertices(GeometrySet &geometry_set, } GeometryComponentFieldContext field_context{*point_component, ATTR_DOMAIN_POINT}; - const int domain_num = point_component->attribute_domain_num(ATTR_DOMAIN_POINT); + const int domain_num = point_component->attribute_domain_size(ATTR_DOMAIN_POINT); if (domain_num == 0) { geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES}); return; @@ -60,18 +60,19 @@ static void geometry_set_points_to_vertices(GeometrySet &geometry_set, for (Map::Item entry : attributes.items()) { const AttributeIDRef attribute_id = entry.key; const eCustomDataType data_type = entry.value.data_type; - GVArray src = point_component->attribute_get_for_read( - attribute_id, ATTR_DOMAIN_POINT, data_type); - OutputAttribute dst = mesh_component.attribute_try_get_for_output_only( + GVArray src = point_component->attributes()->lookup_or_default( attribute_id, ATTR_DOMAIN_POINT, data_type); + GSpanAttributeWriter dst = + mesh_component.attributes_for_write()->lookup_or_add_for_write_only_span( + attribute_id, ATTR_DOMAIN_POINT, data_type); if (dst && src) { attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); VArray src_typed = src.typed(); VArraySpan src_typed_span{src_typed}; - copy_attribute_to_vertices(src_typed_span, selection, dst.as_span().typed()); + copy_attribute_to_vertices(src_typed_span, selection, dst.span.typed()); }); - dst.save(); + dst.finish(); } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc index 42cee4c0efe..28a01a5cbce 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc @@ -163,12 +163,15 @@ static void gather_point_data_from_component(GeoNodeExecParams ¶ms, Vector &r_positions, Vector &r_radii) { - VArray positions = component.attribute_get_for_read( + if (component.is_empty()) { + return; + } + VArray positions = component.attributes()->lookup_or_default( "position", ATTR_DOMAIN_POINT, {0, 0, 0}); Field radius_field = params.get_input>("Radius"); GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT}; - const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_POINT); + const int domain_num = component.attribute_domain_size(ATTR_DOMAIN_POINT); r_positions.resize(r_positions.size() + domain_num); positions.materialize(r_positions.as_mutable_span().take_back(domain_num)); diff --git a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc index a92cee2d066..f81748da587 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc @@ -312,8 +312,8 @@ class RaycastFunction : public fn::MultiFunction { } const MeshComponent &mesh_component = *target_.get_component_for_read(); target_context_.emplace(GeometryComponentFieldContext{mesh_component, domain_}); - const int domain_num = mesh_component.attribute_domain_num(domain_); - target_evaluator_ = std::make_unique(*target_context_, domain_num); + const int domain_size = mesh_component.attribute_domain_size(domain_); + target_evaluator_ = std::make_unique(*target_context_, domain_size); target_evaluator_->add(std::move(src_field)); target_evaluator_->evaluate(); target_data_ = &target_evaluator_->get_evaluated(0); diff --git a/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc index da42b8c5ee0..ee279ba58f9 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc @@ -39,7 +39,7 @@ static void node_geo_exec(GeoNodeExecParams params) /* First check if the attribute exists before getting write access, * to avoid potentially expensive unnecessary copies. */ const GeometryComponent &read_only_component = *geometry_set.get_component_for_read(type); - if (read_only_component.attribute_exists(name)) { + if (read_only_component.attributes()->contains(name)) { attribute_exists = true; } else { @@ -47,7 +47,7 @@ static void node_geo_exec(GeoNodeExecParams params) } GeometryComponent &component = geometry_set.get_component_for_write(type); - if (!component.attribute_try_delete(name)) { + if (!component.attributes_for_write()->remove(name)) { cannot_delete = true; } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc index 37533a7b99a..fc3cb7006bb 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc @@ -75,12 +75,12 @@ static void set_position_in_component(CurveComponent &component, const Field &offset_field) { GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT}; - const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_POINT); - if (domain_num == 0) { + const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT); + if (domain_size == 0) { return; } - fn::FieldEvaluator evaluator{field_context, domain_num}; + fn::FieldEvaluator evaluator{field_context, domain_size}; evaluator.set_selection(selection_field); evaluator.add(position_field); evaluator.add(offset_field); @@ -146,8 +146,8 @@ static void node_geo_exec(GeoNodeExecParams params) } has_curves = true; const CurveComponent &component = *geometry_set.get_component_for_read(); - if (!component.attribute_exists("handle_left") || - !component.attribute_exists("handle_right")) { + const AttributeAccessor attributes = *component.attributes(); + if (!attributes.contains("handle_left") || !attributes.contains("handle_right")) { return; } has_bezier = true; diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc index 4c84093bfcb..90411baac3e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc @@ -20,21 +20,22 @@ static void set_radius_in_component(GeometryComponent &component, const Field &selection_field, const Field &radius_field) { - GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT}; - const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_POINT); - if (domain_num == 0) { + const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT); + if (domain_size == 0) { return; } + MutableAttributeAccessor attributes = *component.attributes_for_write(); + GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT}; - OutputAttribute_Typed radii = component.attribute_try_get_for_output_only( - "radius", ATTR_DOMAIN_POINT); + AttributeWriter radii = attributes.lookup_or_add_for_write("radius", + ATTR_DOMAIN_POINT); - fn::FieldEvaluator evaluator{field_context, domain_num}; + fn::FieldEvaluator evaluator{field_context, domain_size}; evaluator.set_selection(selection_field); - evaluator.add_with_destination(radius_field, radii.varray()); + evaluator.add_with_destination(radius_field, radii.varray); evaluator.evaluate(); - radii.save(); + radii.finish(); } static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc index 8b1e5935a61..2211ac62727 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc @@ -16,21 +16,23 @@ static void set_tilt_in_component(GeometryComponent &component, const Field &selection_field, const Field &tilt_field) { - GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT}; - const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_POINT); - if (domain_num == 0) { + const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT); + if (domain_size == 0) { return; } + MutableAttributeAccessor attributes = *component.attributes_for_write(); + + GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT}; - OutputAttribute_Typed tilts = component.attribute_try_get_for_output_only( - "tilt", ATTR_DOMAIN_POINT); + AttributeWriter tilts = attributes.lookup_or_add_for_write("tilt", + ATTR_DOMAIN_POINT); - fn::FieldEvaluator evaluator{field_context, domain_num}; + fn::FieldEvaluator evaluator{field_context, domain_size}; evaluator.set_selection(selection_field); - evaluator.add_with_destination(tilt_field, tilts.varray()); + evaluator.add_with_destination(tilt_field, tilts.varray); evaluator.evaluate(); - tilts.save(); + tilts.finish(); } static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc index a7f17c02ce8..fbb2ecbb799 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc @@ -19,34 +19,34 @@ static void set_id_in_component(GeometryComponent &component, const eAttrDomain domain = (component.type() == GEO_COMPONENT_TYPE_INSTANCES) ? ATTR_DOMAIN_INSTANCE : ATTR_DOMAIN_POINT; - GeometryComponentFieldContext field_context{component, domain}; - const int domain_num = component.attribute_domain_num(domain); - if (domain_num == 0) { + const int domain_size = component.attribute_domain_size(domain); + if (domain_size == 0) { return; } + MutableAttributeAccessor attributes = *component.attributes_for_write(); + GeometryComponentFieldContext field_context{component, domain}; - fn::FieldEvaluator evaluator{field_context, domain_num}; + fn::FieldEvaluator evaluator{field_context, domain_size}; evaluator.set_selection(selection_field); /* Since adding the ID attribute can change the result of the field evaluation (the random value * node uses the index if the ID is unavailable), make sure that it isn't added before evaluating * the field. However, as an optimization, use a faster code path when it already exists. */ - if (component.attribute_exists("id")) { - OutputAttribute_Typed id_attribute = component.attribute_try_get_for_output_only( - "id", domain); - evaluator.add_with_destination(id_field, id_attribute.varray()); + if (attributes.contains("id")) { + AttributeWriter id_attribute = attributes.lookup_or_add_for_write("id", domain); + evaluator.add_with_destination(id_field, id_attribute.varray); evaluator.evaluate(); - id_attribute.save(); + id_attribute.finish(); } else { evaluator.add(id_field); evaluator.evaluate(); const IndexMask selection = evaluator.get_evaluated_selection_as_mask(); const VArray result_ids = evaluator.get_evaluated(0); - OutputAttribute_Typed id_attribute = component.attribute_try_get_for_output_only( - "id", domain); - result_ids.materialize(selection, id_attribute.as_span()); - id_attribute.save(); + SpanAttributeWriter id_attribute = attributes.lookup_or_add_for_write_span("id", + domain); + result_ids.materialize(selection, id_attribute.span); + id_attribute.finish(); } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc index 58613dae832..0dc89bb7ef4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc @@ -16,20 +16,21 @@ static void set_material_index_in_component(GeometryComponent &component, const Field &selection_field, const Field &index_field) { - GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE}; - const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_FACE); - if (domain_num == 0) { + const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE); + if (domain_size == 0) { return; } + MutableAttributeAccessor attributes = *component.attributes_for_write(); + GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE}; - OutputAttribute_Typed indices = component.attribute_try_get_for_output_only( - "material_index", ATTR_DOMAIN_FACE); + AttributeWriter indices = attributes.lookup_or_add_for_write("material_index", + ATTR_DOMAIN_FACE); - fn::FieldEvaluator evaluator{field_context, domain_num}; + fn::FieldEvaluator evaluator{field_context, domain_size}; evaluator.set_selection(selection_field); - evaluator.add_with_destination(index_field, indices.varray()); + evaluator.add_with_destination(index_field, indices.varray); evaluator.evaluate(); - indices.save(); + indices.finish(); } static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc index 571bead9743..da7977a4fb4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc @@ -20,21 +20,22 @@ static void set_radius_in_component(GeometryComponent &component, const Field &selection_field, const Field &radius_field) { - GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT}; - const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_POINT); - if (domain_num == 0) { + const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT); + if (domain_size == 0) { return; } + MutableAttributeAccessor attributes = *component.attributes_for_write(); + GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT}; - OutputAttribute_Typed radii = component.attribute_try_get_for_output_only( - "radius", ATTR_DOMAIN_POINT); + AttributeWriter radii = attributes.lookup_or_add_for_write("radius", + ATTR_DOMAIN_POINT); - fn::FieldEvaluator evaluator{field_context, domain_num}; + fn::FieldEvaluator evaluator{field_context, domain_size}; evaluator.set_selection(selection_field); - evaluator.add_with_destination(radius_field, radii.varray()); + evaluator.add_with_destination(radius_field, radii.varray); evaluator.evaluate(); - radii.save(); + radii.finish(); } static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc index 1935409b3e5..880252de4fa 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc @@ -25,12 +25,10 @@ static void node_declare(NodeDeclarationBuilder &b) static void set_computed_position_and_offset(GeometryComponent &component, const VArray &in_positions, const VArray &in_offsets, - const eAttrDomain domain, const IndexMask selection) { - - OutputAttribute_Typed positions = component.attribute_try_get_for_output( - "position", domain, {0, 0, 0}); + MutableAttributeAccessor attributes = *component.attributes_for_write(); + AttributeWriter positions = attributes.lookup_for_write("position"); const int grain_size = 10000; @@ -38,7 +36,7 @@ static void set_computed_position_and_offset(GeometryComponent &component, case GEO_COMPONENT_TYPE_MESH: { Mesh *mesh = static_cast(component).get_for_write(); MutableSpan mverts{mesh->mvert, mesh->totvert}; - if (in_positions.is_same(positions.varray())) { + if (in_positions.is_same(positions.varray)) { devirtualize_varray(in_offsets, [&](const auto in_offsets) { threading::parallel_for( selection.index_range(), grain_size, [&](const IndexRange range) { @@ -67,18 +65,13 @@ static void set_computed_position_and_offset(GeometryComponent &component, CurveComponent &curve_component = static_cast(component); Curves &curves_id = *curve_component.get_for_write(); bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry); - if (component.attribute_exists("handle_right") && - component.attribute_exists("handle_left")) { - OutputAttribute_Typed handle_right_attribute = - component.attribute_try_get_for_output( - "handle_right", ATTR_DOMAIN_POINT, {0, 0, 0}); - OutputAttribute_Typed handle_left_attribute = - component.attribute_try_get_for_output( - "handle_left", ATTR_DOMAIN_POINT, {0, 0, 0}); - MutableSpan handle_right = handle_right_attribute.as_span(); - MutableSpan handle_left = handle_left_attribute.as_span(); - - MutableSpan out_positions_span = positions.as_span(); + if (attributes.contains("handle_right") && attributes.contains("handle_left")) { + SpanAttributeWriter handle_right_attribute = + attributes.lookup_or_add_for_write_span("handle_right", ATTR_DOMAIN_POINT); + SpanAttributeWriter handle_left_attribute = + attributes.lookup_or_add_for_write_span("handle_left", ATTR_DOMAIN_POINT); + + MutableVArraySpan out_positions_span = positions.varray; devirtualize_varray2( in_positions, in_offsets, [&](const auto in_positions, const auto in_offsets) { threading::parallel_for( @@ -86,15 +79,16 @@ static void set_computed_position_and_offset(GeometryComponent &component, for (const int i : selection.slice(range)) { const float3 new_position = in_positions[i] + in_offsets[i]; const float3 delta = new_position - out_positions_span[i]; - handle_right[i] += delta; - handle_left[i] += delta; + handle_right_attribute.span[i] += delta; + handle_left_attribute.span[i] += delta; out_positions_span[i] = new_position; } }); }); - handle_right_attribute.save(); - handle_left_attribute.save(); + out_positions_span.save(); + handle_right_attribute.finish(); + handle_left_attribute.finish(); /* Automatic Bezier handles must be recalculated based on the new positions. */ curves.calculate_bezier_auto_handles(); @@ -105,8 +99,8 @@ static void set_computed_position_and_offset(GeometryComponent &component, } } default: { - MutableSpan out_positions_span = positions.as_span(); - if (in_positions.is_same(positions.varray())) { + MutableVArraySpan out_positions_span = positions.varray; + if (in_positions.is_same(positions.varray)) { devirtualize_varray(in_offsets, [&](const auto in_offsets) { threading::parallel_for( selection.index_range(), grain_size, [&](const IndexRange range) { @@ -127,11 +121,12 @@ static void set_computed_position_and_offset(GeometryComponent &component, }); }); } + out_positions_span.save(); break; } } - positions.save(); + positions.finish(); } static void set_position_in_component(GeometryComponent &component, @@ -142,21 +137,22 @@ static void set_position_in_component(GeometryComponent &component, eAttrDomain domain = component.type() == GEO_COMPONENT_TYPE_INSTANCES ? ATTR_DOMAIN_INSTANCE : ATTR_DOMAIN_POINT; GeometryComponentFieldContext field_context{component, domain}; - const int domain_num = component.attribute_domain_num(domain); - if (domain_num == 0) { + const int domain_size = component.attribute_domain_size(domain); + if (domain_size == 0) { return; } - fn::FieldEvaluator evaluator{field_context, domain_num}; + fn::FieldEvaluator evaluator{field_context, domain_size}; evaluator.set_selection(selection_field); evaluator.add(position_field); evaluator.add(offset_field); evaluator.evaluate(); const IndexMask selection = evaluator.get_evaluated_selection_as_mask(); + const VArray positions_input = evaluator.get_evaluated(0); const VArray offsets_input = evaluator.get_evaluated(1); - set_computed_position_and_offset(component, positions_input, offsets_input, domain, selection); + set_computed_position_and_offset(component, positions_input, offsets_input, selection); } static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc index b98fbd0a0fe..e0cf0f98d58 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc @@ -16,21 +16,23 @@ static void set_smooth_in_component(GeometryComponent &component, const Field &selection_field, const Field &shade_field) { - GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE}; - const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_FACE); - if (domain_num == 0) { + const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE); + if (domain_size == 0) { return; } + MutableAttributeAccessor attributes = *component.attributes_for_write(); + + GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE}; - OutputAttribute_Typed shades = component.attribute_try_get_for_output_only( - "shade_smooth", ATTR_DOMAIN_FACE); + AttributeWriter shades = attributes.lookup_or_add_for_write("shade_smooth", + ATTR_DOMAIN_FACE); - fn::FieldEvaluator evaluator{field_context, domain_num}; + fn::FieldEvaluator evaluator{field_context, domain_size}; evaluator.set_selection(selection_field); - evaluator.add_with_destination(shade_field, shades.varray()); + evaluator.add_with_destination(shade_field, shades.varray); evaluator.evaluate(); - shades.save(); + shades.finish(); } static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc index 976857883f0..a35d8d66558 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc @@ -16,21 +16,23 @@ static void set_cyclic_in_component(GeometryComponent &component, const Field &selection_field, const Field &cyclic_field) { - GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE}; - const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_CURVE); - if (domain_num == 0) { + const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE); + if (domain_size == 0) { return; } + MutableAttributeAccessor attributes = *component.attributes_for_write(); + + GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE}; - OutputAttribute_Typed cyclics = component.attribute_try_get_for_output_only( - "cyclic", ATTR_DOMAIN_CURVE); + AttributeWriter cyclics = attributes.lookup_or_add_for_write("cyclic", + ATTR_DOMAIN_CURVE); - fn::FieldEvaluator evaluator{field_context, domain_num}; + fn::FieldEvaluator evaluator{field_context, domain_size}; evaluator.set_selection(selection_field); - evaluator.add_with_destination(cyclic_field, cyclics.varray()); + evaluator.add_with_destination(cyclic_field, cyclics.varray); evaluator.evaluate(); - cyclics.save(); + cyclics.finish(); } static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc index 8b665376c01..fcebc1116d7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc @@ -16,21 +16,23 @@ static void set_resolution_in_component(GeometryComponent &component, const Field &selection_field, const Field &resolution_field) { - GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE}; - const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_CURVE); - if (domain_num == 0) { + const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE); + if (domain_size == 0) { return; } + MutableAttributeAccessor attributes = *component.attributes_for_write(); + + GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE}; - OutputAttribute_Typed resolutions = component.attribute_try_get_for_output_only( - "resolution", ATTR_DOMAIN_CURVE); + AttributeWriter resolutions = attributes.lookup_or_add_for_write("resolution", + ATTR_DOMAIN_CURVE); - fn::FieldEvaluator evaluator{field_context, domain_num}; + fn::FieldEvaluator evaluator{field_context, domain_size}; evaluator.set_selection(selection_field); - evaluator.add_with_destination(resolution_field, resolutions.varray()); + evaluator.add_with_destination(resolution_field, resolutions.varray); evaluator.evaluate(); - resolutions.save(); + resolutions.finish(); } static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc index abac6d8d6b3..69a4fad10e2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc @@ -87,9 +87,14 @@ static void try_capture_field_on_geometry(GeometryComponent &component, const eAttrDomain domain, const GField &field) { + const int domain_size = component.attribute_domain_size(domain); + if (domain_size == 0) { + return; + } + MutableAttributeAccessor attributes = *component.attributes_for_write(); + GeometryComponentFieldContext field_context{component, domain}; - const int domain_num = component.attribute_domain_num(domain); - const IndexMask mask{IndexMask(domain_num)}; + const IndexMask mask{IndexMask(domain_size)}; const CPPType &type = field.cpp_type(); const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(type); @@ -97,28 +102,28 @@ static void try_capture_field_on_geometry(GeometryComponent &component, /* Could avoid allocating a new buffer if: * - We are writing to an attribute that exists already. * - The field does not depend on that attribute (we can't easily check for that yet). */ - void *buffer = MEM_mallocN(type.size() * domain_num, __func__); + void *buffer = MEM_mallocN(type.size() * domain_size, __func__); fn::FieldEvaluator evaluator{field_context, &mask}; - evaluator.add_with_destination(field, GMutableSpan{type, buffer, domain_num}); + evaluator.add_with_destination(field, GMutableSpan{type, buffer, domain_size}); evaluator.evaluate(); - component.attribute_try_delete(name); - if (component.attribute_exists(name)) { - WriteAttributeLookup write_attribute = component.attribute_try_get_for_write(name); + attributes.remove(name); + if (attributes.contains(name)) { + GAttributeWriter write_attribute = attributes.lookup_for_write(name); if (write_attribute && write_attribute.domain == domain && write_attribute.varray.type() == type) { write_attribute.varray.set_all(buffer); - write_attribute.tag_modified_fn(); + write_attribute.finish(); } else { /* Cannot change type of built-in attribute. */ } - type.destruct_n(buffer, domain_num); + type.destruct_n(buffer, domain_size); MEM_freeN(buffer); } else { - if (!component.attribute_try_create(name, domain, data_type, AttributeInitMove{buffer})) { + if (!attributes.add(name, domain, data_type, bke::AttributeInitMove{buffer})) { MEM_freeN(buffer); } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc index 94d5d7f946f..afd7db6604d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc @@ -335,13 +335,14 @@ static void create_attributes(GeoNodeExecParams ¶ms, const TextLayout &layout, InstancesComponent &instances) { + MutableAttributeAccessor attributes = *instances.attributes_for_write(); + if (params.output_is_required("Line")) { StrongAnonymousAttributeID line_id = StrongAnonymousAttributeID("Line"); - OutputAttribute_Typed line_attribute = instances.attribute_try_get_for_output_only( + SpanAttributeWriter line_attribute = attributes.lookup_or_add_for_write_only_span( line_id.get(), ATTR_DOMAIN_INSTANCE); - MutableSpan lines = line_attribute.as_span(); - lines.copy_from(layout.line_numbers); - line_attribute.save(); + line_attribute.span.copy_from(layout.line_numbers); + line_attribute.finish(); params.set_output("Line", AnonymousAttributeFieldInput::Create(std::move(line_id), params.attribute_producer_name())); @@ -349,15 +350,14 @@ static void create_attributes(GeoNodeExecParams ¶ms, if (params.output_is_required("Pivot Point")) { StrongAnonymousAttributeID pivot_id = StrongAnonymousAttributeID("Pivot"); - OutputAttribute_Typed pivot_attribute = - instances.attribute_try_get_for_output_only(pivot_id.get(), ATTR_DOMAIN_INSTANCE); - MutableSpan pivots = pivot_attribute.as_span(); + SpanAttributeWriter pivot_attribute = + attributes.lookup_or_add_for_write_only_span(pivot_id.get(), ATTR_DOMAIN_INSTANCE); for (const int i : layout.char_codes.index_range()) { - pivots[i] = layout.pivot_points.lookup(layout.char_codes[i]); + pivot_attribute.span[i] = layout.pivot_points.lookup(layout.char_codes[i]); } - pivot_attribute.save(); + pivot_attribute.finish(); params.set_output("Pivot Point", AnonymousAttributeFieldInput::Create( std::move(pivot_id), params.attribute_producer_name())); diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc index 9eda5bb34ff..eda6a51d412 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc @@ -6,6 +6,7 @@ #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" +#include "BKE_attribute.hh" #include "BKE_mesh.h" #include "BKE_subdiv.h" #include "BKE_subdiv_mesh.h" @@ -79,10 +80,11 @@ static void write_vertex_creases(Mesh &mesh, const VArray &crease_varray) static void write_edge_creases(MeshComponent &mesh, const VArray &crease_varray) { - OutputAttribute_Typed attribute = mesh.attribute_try_get_for_output_only( - "crease", ATTR_DOMAIN_EDGE); - materialize_and_clamp_creases(crease_varray, attribute.as_span()); - attribute.save(); + bke::SpanAttributeWriter attribute = + mesh.attributes_for_write()->lookup_or_add_for_write_only_span("crease", + ATTR_DOMAIN_EDGE); + materialize_and_clamp_creases(crease_varray, attribute.span); + attribute.finish(); } static bool varray_is_nonzero(const VArray &varray) @@ -118,8 +120,8 @@ static void node_geo_exec(GeoNodeExecParams params) } const MeshComponent &mesh_component = *geometry_set.get_component_for_read(); - const int verts_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_POINT); - const int edges_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_EDGE); + const int verts_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT); + const int edges_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_EDGE); if (verts_num == 0 || edges_num == 0) { return; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc index 0af6c76feaf..cd75822f665 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc @@ -365,7 +365,7 @@ static bool component_is_available(const GeometrySet &geometry, if (component.is_empty()) { return false; } - return component.attribute_domain_num(domain) != 0; + return component.attribute_domain_size(domain) != 0; } /** @@ -433,7 +433,7 @@ class NearestInterpolatedTransferFunction : public fn::MultiFunction { { const MeshComponent &mesh_component = *source_.get_component_for_read(); source_context_.emplace(GeometryComponentFieldContext{mesh_component, domain_}); - const int domain_num = mesh_component.attribute_domain_num(domain_); + const int domain_num = mesh_component.attribute_domain_size(domain_); source_evaluator_ = std::make_unique(*source_context_, domain_num); source_evaluator_->add(src_field_); source_evaluator_->evaluate(); @@ -578,7 +578,7 @@ class NearestTransferFunction : public fn::MultiFunction { { if (use_mesh_) { const MeshComponent &mesh = *source_.get_component_for_read(); - const int domain_num = mesh.attribute_domain_num(domain_); + const int domain_num = mesh.attribute_domain_size(domain_); mesh_context_.emplace(GeometryComponentFieldContext(mesh, domain_)); mesh_evaluator_ = std::make_unique(*mesh_context_, domain_num); mesh_evaluator_->add(src_field_); @@ -588,7 +588,7 @@ class NearestTransferFunction : public fn::MultiFunction { if (use_points_) { const PointCloudComponent &points = *source_.get_component_for_read(); - const int domain_num = points.attribute_domain_num(domain_); + const int domain_num = points.attribute_domain_size(domain_); point_context_.emplace(GeometryComponentFieldContext(points, domain_)); point_evaluator_ = std::make_unique(*point_context_, domain_num); point_evaluator_->add(src_field_); @@ -658,7 +658,7 @@ class IndexTransferFunction : public fn::MultiFunction { if (component == nullptr) { return; } - const int domain_num = component->attribute_domain_num(domain_); + const int domain_num = component->attribute_domain_size(domain_); geometry_context_.emplace(GeometryComponentFieldContext(*component, domain_)); evaluator_ = std::make_unique(*geometry_context_, domain_num); evaluator_->add(src_field_); diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc index e47dc22da04..992470e8279 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc @@ -83,9 +83,9 @@ static void node_geo_exec(GeoNodeExecParams params) GeometryComponent &component = geometry_set.get_component_for_write(); const Mesh &mesh_in = *geometry_set.get_mesh_for_read(); - const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_FACE); + const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE); GeometryComponentFieldContext context{component, ATTR_DOMAIN_FACE}; - FieldEvaluator evaluator{context, domain_num}; + FieldEvaluator evaluator{context, domain_size}; evaluator.add(selection_field); evaluator.evaluate(); const IndexMask selection = evaluator.get_evaluated_as_mask(0); diff --git a/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc b/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc index feff6efc3f8..17413e64f7d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc @@ -40,7 +40,7 @@ static VArray construct_uv_gvarray(const MeshComponent &component, return {}; } - const int face_num = component.attribute_domain_num(ATTR_DOMAIN_FACE); + const int face_num = component.attribute_domain_size(ATTR_DOMAIN_FACE); GeometryComponentFieldContext face_context{component, ATTR_DOMAIN_FACE}; FieldEvaluator face_evaluator{face_context, face_num}; face_evaluator.add(selection_field); @@ -50,7 +50,7 @@ static VArray construct_uv_gvarray(const MeshComponent &component, return {}; } - const int corner_num = component.attribute_domain_num(ATTR_DOMAIN_CORNER); + const int corner_num = component.attribute_domain_size(ATTR_DOMAIN_CORNER); GeometryComponentFieldContext corner_context{component, ATTR_DOMAIN_CORNER}; FieldEvaluator evaluator{corner_context, corner_num}; Array uv(corner_num); @@ -88,7 +88,7 @@ static VArray construct_uv_gvarray(const MeshComponent &component, GEO_uv_parametrizer_flush(handle); GEO_uv_parametrizer_delete(handle); - return component.attribute_try_adapt_domain( + return component.attributes()->adapt_domain( VArray::ForContainer(std::move(uv)), ATTR_DOMAIN_CORNER, domain); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc b/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc index 364106455b6..2ec14ad2d29 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc @@ -65,7 +65,7 @@ static VArray construct_uv_gvarray(const MeshComponent &component, return {}; } - const int face_num = component.attribute_domain_num(ATTR_DOMAIN_FACE); + const int face_num = component.attribute_domain_size(ATTR_DOMAIN_FACE); GeometryComponentFieldContext face_context{component, ATTR_DOMAIN_FACE}; FieldEvaluator face_evaluator{face_context, face_num}; face_evaluator.add(selection_field); @@ -75,7 +75,7 @@ static VArray construct_uv_gvarray(const MeshComponent &component, return {}; } - const int edge_num = component.attribute_domain_num(ATTR_DOMAIN_EDGE); + const int edge_num = component.attribute_domain_size(ATTR_DOMAIN_EDGE); GeometryComponentFieldContext edge_context{component, ATTR_DOMAIN_EDGE}; FieldEvaluator edge_evaluator{edge_context, edge_num}; edge_evaluator.add(seam_field); @@ -126,7 +126,7 @@ static VArray construct_uv_gvarray(const MeshComponent &component, GEO_uv_parametrizer_flush(handle); GEO_uv_parametrizer_delete(handle); - return component.attribute_try_adapt_domain( + return component.attributes()->adapt_domain( VArray::ForContainer(std::move(uv)), ATTR_DOMAIN_CORNER, domain); } diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc index 85dfdf03b82..cf7cbbdc4bf 100644 --- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc +++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc @@ -228,7 +228,7 @@ GeometryValueLog::GeometryValueLog(const GeometrySet &geometry_set, bool log_ful all_component_types, true, [&](const bke::AttributeIDRef &attribute_id, - const AttributeMetaData &meta_data, + const bke::AttributeMetaData &meta_data, const GeometryComponent &UNUSED(component)) { if (attribute_id.is_named() && names.add(attribute_id.name())) { this->attributes_.append({attribute_id.name(), meta_data.domain, meta_data.data_type}); @@ -241,21 +241,21 @@ GeometryValueLog::GeometryValueLog(const GeometrySet &geometry_set, bool log_ful case GEO_COMPONENT_TYPE_MESH: { const MeshComponent &mesh_component = *(const MeshComponent *)component; MeshInfo &info = this->mesh_info.emplace(); - info.verts_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_POINT); - info.edges_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_EDGE); - info.faces_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_FACE); + info.verts_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT); + info.edges_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_EDGE); + info.faces_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_FACE); break; } case GEO_COMPONENT_TYPE_CURVE: { const CurveComponent &curve_component = *(const CurveComponent *)component; CurveInfo &info = this->curve_info.emplace(); - info.splines_num = curve_component.attribute_domain_num(ATTR_DOMAIN_CURVE); + info.splines_num = curve_component.attribute_domain_size(ATTR_DOMAIN_CURVE); break; } case GEO_COMPONENT_TYPE_POINT_CLOUD: { const PointCloudComponent &pointcloud_component = *(const PointCloudComponent *)component; PointCloudInfo &info = this->pointcloud_info.emplace(); - info.points_num = pointcloud_component.attribute_domain_num(ATTR_DOMAIN_POINT); + info.points_num = pointcloud_component.attribute_domain_size(ATTR_DOMAIN_POINT); break; } case GEO_COMPONENT_TYPE_INSTANCES: { -- cgit v1.2.3