diff options
Diffstat (limited to 'source/blender/blenkernel/BKE_geometry_set.hh')
-rw-r--r-- | source/blender/blenkernel/BKE_geometry_set.hh | 243 |
1 files changed, 140 insertions, 103 deletions
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index d94b2e7902b..027338a5d5c 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -56,72 +56,77 @@ class ComponentAttributeProviders; class GeometryComponent; /** - * An #OutputAttributePtr wraps a #WriteAttributePtr that might not be stored in its final - * destination yet. Therefore, once the attribute has been filled with data, the #save method has - * to be called, to store the attribute where it belongs (possibly by replacing an existing - * attribute with the same name). - * - * This is useful for example in the Attribute Color Ramp node, when the same attribute name is - * used as input and output. Typically the input is a float attribute, and the output is a color. - * Those two attributes cannot exist at the same time, due to a name collision. To handle this - * situation well, first the output colors have to be computed before the input floats are deleted. - * Therefore, the outputs have to be written to a temporary buffer that replaces the existing - * attribute once all computations are done. + * 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, ...). */ -class OutputAttributePtr { - private: - blender::bke::WriteAttributePtr attribute_; - - public: - OutputAttributePtr() = default; - OutputAttributePtr(blender::bke::WriteAttributePtr attribute); - OutputAttributePtr(GeometryComponent &component, - AttributeDomain domain, - std::string name, - CustomDataType data_type); +struct AttributeMetaData { + AttributeDomain domain; + CustomDataType data_type; +}; - ~OutputAttributePtr(); +/* Returns false when the iteration should be stopped. */ +using AttributeForeachCallback = blender::FunctionRef<bool(blender::StringRefNull attribute_name, + const AttributeMetaData &meta_data)>; - /* Returns false, when this wrapper is empty. */ - operator bool() const +/** + * Base class for the attribute intializer types described below. + */ +struct AttributeInit { + enum class Type { + Default, + VArray, + MoveArray, + }; + Type type; + AttributeInit(const Type type) : type(type) { - return static_cast<bool>(attribute_); } +}; - /* Get a reference to the underlying #WriteAttribute. */ - blender::bke::WriteAttribute &get() +/** + * 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) { - BLI_assert(attribute_); - return *attribute_; } +}; - blender::bke::WriteAttribute &operator*() - { - return *attribute_; - } +/** + * 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 { + const blender::fn::GVArray *varray; - blender::bke::WriteAttribute *operator->() + AttributeInitVArray(const blender::fn::GVArray *varray) + : AttributeInit(Type::VArray), varray(varray) { - return attribute_.get(); } - - void save(); - void apply_span_and_save(); }; /** - * 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, ...). + * 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 contigious + * 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 AttributeMetaData { - AttributeDomain domain; - CustomDataType data_type; -}; +struct AttributeInitMove : public AttributeInit { + void *data = nullptr; -/* Returns false when the iteration should be stopped. */ -using AttributeForeachCallback = blender::FunctionRef<bool(blender::StringRefNull attribute_name, - const AttributeMetaData &meta_data)>; + AttributeInitMove(void *data) : AttributeInit(Type::MoveArray), data(data) + { + } +}; /** * This is the base class for specialized geometry component types. @@ -156,26 +161,34 @@ class GeometryComponent { /* Return true when any attribute with this name exists, including built in attributes. */ bool attribute_exists(const blender::StringRef attribute_name) const; + /* Return the data type and domain of an attribute with the given name if it exists. */ + std::optional<AttributeMetaData> attribute_get_meta_data( + const blender::StringRef attribute_name) const; + /* Returns true when the geometry component supports this attribute domain. */ bool attribute_domain_supported(const AttributeDomain domain) const; /* Can only be used with supported domain types. */ virtual int attribute_domain_size(const AttributeDomain domain) const; + bool attribute_is_builtin(const blender::StringRef attribute_name) const; + /* Get read-only access to the highest priority attribute with the given name. * Returns null if the attribute does not exist. */ - blender::bke::ReadAttributePtr attribute_try_get_for_read( + blender::bke::ReadAttributeLookup attribute_try_get_for_read( const blender::StringRef attribute_name) const; /* Get read and write access to the highest priority attribute with the given name. * Returns null if the attribute does not exist. */ - blender::bke::WriteAttributePtr attribute_try_get_for_write( + blender::bke::WriteAttributeLookup attribute_try_get_for_write( const blender::StringRef attribute_name); /* Get a read-only attribute for the domain based on the given attribute. This can be used to * interpolate from one domain to another. * Returns null if the interpolation is not implemented. */ - virtual blender::bke::ReadAttributePtr attribute_try_adapt_domain( - blender::bke::ReadAttributePtr attribute, const AttributeDomain new_domain) const; + virtual std::unique_ptr<blender::fn::GVArray> attribute_try_adapt_domain( + std::unique_ptr<blender::fn::GVArray> varray, + const AttributeDomain from_domain, + const AttributeDomain to_domain) const; /* Returns true when the attribute has been deleted. */ bool attribute_try_delete(const blender::StringRef attribute_name); @@ -183,82 +196,104 @@ class GeometryComponent { /* Returns true when the attribute has been created. */ bool attribute_try_create(const blender::StringRef attribute_name, const AttributeDomain domain, - const CustomDataType data_type); + const CustomDataType 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<std::string> attribute_names() const; bool attribute_foreach(const AttributeForeachCallback callback) const; virtual bool is_empty() const; - /* Get a read-only attribute for the given domain and data type. - * Returns null when it does not exist. */ - blender::bke::ReadAttributePtr attribute_try_get_for_read( + /* Get a virtual array to read the data of an attribute on the given domain and data type. + * Returns null when the attribute does not exist or cannot be converted to the requested domain + * and data type. */ + std::unique_ptr<blender::fn::GVArray> attribute_try_get_for_read( const blender::StringRef attribute_name, const AttributeDomain domain, const CustomDataType data_type) const; - /* Get a read-only attribute interpolated to the input domain, leaving the data type unchanged. - * Returns null when the attribute does not exist. */ - blender::bke::ReadAttributePtr attribute_try_get_for_read( + /* Get a virtual array to read the data of an attribute on the given domain. The data type is + * left unchanged. Returns null when the attribute does not exist or cannot be adapted to the + * requested domain. */ + std::unique_ptr<blender::fn::GVArray> attribute_try_get_for_read( const blender::StringRef attribute_name, const AttributeDomain domain) const; - /* Get a read-only attribute for the given domain and data type. - * Returns a constant attribute based on the default value if the attribute does not exist. - * Never returns null. */ - blender::bke::ReadAttributePtr attribute_get_for_read(const blender::StringRef attribute_name, - const AttributeDomain domain, - const CustomDataType data_type, - const void *default_value) const; + /* Get a virtual array to read data of an attribute with the given data type. The domain is + * left unchanged. Returns null when the attribute does not exist or cannot be converted to the + * requested data type. */ + blender::bke::ReadAttributeLookup attribute_try_get_for_read( + const blender::StringRef attribute_name, const CustomDataType data_type) const; - /* Get a typed read-only attribute for the given domain and type. */ - template<typename T> - blender::bke::TypedReadAttribute<T> attribute_get_for_read( + /* Get a virtual array to read the data of an attribute. If that is not possible, the returned + * virtual array will contain a default value. This never returns null. */ + std::unique_ptr<blender::fn::GVArray> attribute_get_for_read( const blender::StringRef attribute_name, const AttributeDomain domain, - const T &default_value) const + const CustomDataType data_type, + const void *default_value = nullptr) const; + + /* Should be used instead of the method above when the requested data type is known at compile + * time for better type safety. */ + template<typename T> + blender::fn::GVArray_Typed<T> attribute_get_for_read(const blender::StringRef attribute_name, + const AttributeDomain domain, + const T &default_value) const { const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>(); const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type); - return this->attribute_get_for_read(attribute_name, domain, type, &default_value); + std::unique_ptr varray = this->attribute_get_for_read( + attribute_name, domain, type, &default_value); + return blender::fn::GVArray_Typed<T>(std::move(varray)); } - /* Get a read-only dummy attribute that always returns the same value. */ - blender::bke::ReadAttributePtr attribute_get_constant_for_read(const AttributeDomain domain, - const CustomDataType data_type, - const void *value) const; + /** + * 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::StringRef attribute_name, + const AttributeDomain domain, + const CustomDataType data_type, + const void *default_value = nullptr); - /* Create a read-only dummy attribute that always returns the same value. - * The given value is converted to the correct type if necessary. */ - blender::bke::ReadAttributePtr attribute_get_constant_for_read_converted( + /* 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. Since values are not read + * from this attribute, no default value is necessary. */ + blender::bke::OutputAttribute attribute_try_get_for_output_only( + const blender::StringRef attribute_name, const AttributeDomain domain, - const CustomDataType in_data_type, - const CustomDataType out_data_type, - const void *value) const; + const CustomDataType data_type); - /* Get a read-only dummy attribute that always returns the same value. */ + /* Statically typed method corresponding to the equally named generic one. */ template<typename T> - blender::bke::TypedReadAttribute<T> attribute_get_constant_for_read(const AttributeDomain domain, - const T &value) const + blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output( + const blender::StringRef attribute_name, const AttributeDomain domain, const T default_value) { const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>(); - const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type); - return this->attribute_get_constant_for_read(domain, type, &value); + const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type); + return this->attribute_try_get_for_output(attribute_name, domain, data_type, &default_value); } - /** - * If an attribute with the given params exist, it is returned. - * If no attribute with the given name exists, create it and - * fill it with the default value if it is provided. - * If an attribute with the given name but different domain or type exists, a temporary attribute - * is created that has to be saved after the output has been computed. This avoids deleting - * another attribute, before a computation is finished. - * - * This might return no attribute when the attribute cannot exist on the component. - */ - OutputAttributePtr attribute_try_get_for_output(const blender::StringRef attribute_name, - const AttributeDomain domain, - const CustomDataType data_type, - const void *default_value = nullptr); + /* Statically typed method corresponding to the equally named generic one. */ + template<typename T> + blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output_only( + const blender::StringRef attribute_name, const AttributeDomain domain) + { + const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>(); + const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type); + return this->attribute_try_get_for_output_only(attribute_name, domain, data_type); + } private: virtual const blender::bke::ComponentAttributeProviders *get_attribute_providers() const; @@ -377,8 +412,10 @@ class MeshComponent : public GeometryComponent { Mesh *get_for_write(); int attribute_domain_size(const AttributeDomain domain) const final; - blender::bke::ReadAttributePtr attribute_try_adapt_domain( - blender::bke::ReadAttributePtr attribute, const AttributeDomain new_domain) const final; + std::unique_ptr<blender::fn::GVArray> attribute_try_adapt_domain( + std::unique_ptr<blender::fn::GVArray> varray, + const AttributeDomain from_domain, + const AttributeDomain to_domain) const final; bool is_empty() const final; |