Differential D15514 Diff 53921 source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc
Changeset View
Changeset View
Standalone View
Standalone View
source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc
| /* SPDX-License-Identifier: GPL-2.0-or-later */ | /* SPDX-License-Identifier: GPL-2.0-or-later */ | ||||
| #include <atomic> | |||||
| #include "UI_interface.h" | #include "UI_interface.h" | ||||
| #include "UI_resources.h" | #include "UI_resources.h" | ||||
| #include "RNA_enum_types.h" | |||||
| #include "NOD_socket_search_link.hh" | #include "NOD_socket_search_link.hh" | ||||
| #include "BKE_type_conversions.hh" | #include "BKE_type_conversions.hh" | ||||
| #include "node_geometry_util.hh" | #include "node_geometry_util.hh" | ||||
| namespace blender::nodes::node_geo_store_named_attribute_cc { | namespace blender::nodes::node_geo_store_named_attribute_cc { | ||||
| ▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | if (type && *type != CD_PROP_STRING) { | ||||
| }); | }); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void try_capture_field_on_geometry(GeometryComponent &component, | static void try_capture_field_on_geometry(GeometryComponent &component, | ||||
| const StringRef name, | const StringRef name, | ||||
| const eAttrDomain domain, | const eAttrDomain domain, | ||||
| const GField &field) | const GField &field, | ||||
| std::atomic<bool> &failure) | |||||
JacquesLucke: Use `r_` for output parameters. | |||||
| { | { | ||||
| const int domain_size = component.attribute_domain_size(domain); | const int domain_size = component.attribute_domain_size(domain); | ||||
| if (domain_size == 0) { | if (domain_size == 0) { | ||||
| return; | return; | ||||
| } | } | ||||
| MutableAttributeAccessor attributes = *component.attributes_for_write(); | MutableAttributeAccessor attributes = *component.attributes_for_write(); | ||||
| GeometryComponentFieldContext field_context{component, domain}; | GeometryComponentFieldContext field_context{component, domain}; | ||||
| const IndexMask mask{IndexMask(domain_size)}; | const IndexMask mask{IndexMask(domain_size)}; | ||||
| const CPPType &type = field.cpp_type(); | const CPPType &type = field.cpp_type(); | ||||
| const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(type); | const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(type); | ||||
| /* Could avoid allocating a new buffer if: | /* Could avoid allocating a new buffer if: | ||||
| * - We are writing to an attribute that exists already. | * - We are writing to an attribute that exists already with the correct domain and type. | ||||
| * - The field does not depend on that attribute (we can't easily check for that yet). */ | * - The field does not depend on that attribute (we can't easily check for that yet). */ | ||||
| void *buffer = MEM_mallocN(type.size() * domain_size, __func__); | void *buffer = MEM_mallocN(type.size() * domain_size, __func__); | ||||
| fn::FieldEvaluator evaluator{field_context, &mask}; | fn::FieldEvaluator evaluator{field_context, &mask}; | ||||
| evaluator.add_with_destination(field, GMutableSpan{type, buffer, domain_size}); | evaluator.add_with_destination(field, GMutableSpan{type, buffer, domain_size}); | ||||
| evaluator.evaluate(); | evaluator.evaluate(); | ||||
| attributes.remove(name); | if (std::optional<bke::AttributeMetaData> meta_data = attributes.lookup_meta_data(name)) { | ||||
| if (attributes.contains(name)) { | if (meta_data->domain == domain && meta_data->data_type == data_type) { | ||||
| GAttributeWriter write_attribute = attributes.lookup_for_write(name); | GAttributeWriter write_attribute = attributes.lookup_for_write(name); | ||||
angavrilovUnsubmitted Not Done Inline ActionsThe previous code seems to check domain and type after lookup_for_write, and also checks write_attribute for null. So I wonder if it is really necessary to do separate lookup_meta_data, and whether something might crash if lookup_for_write somehow failed. But I have no clue about this code, this is just observations from this diff alone. angavrilov: The previous code seems to check domain and type after lookup_for_write, and also checks… | |||||
HooglyBooglyAuthorUnsubmitted Done Inline ActionsThanks, good point! HooglyBoogly: Thanks, good point! | |||||
| if (write_attribute && write_attribute.domain == domain && | |||||
| write_attribute.varray.type() == type) { | |||||
| write_attribute.varray.set_all(buffer); | write_attribute.varray.set_all(buffer); | ||||
| write_attribute.finish(); | write_attribute.finish(); | ||||
| } | |||||
| else { | |||||
| /* Cannot change type of built-in attribute. */ | |||||
| } | |||||
| type.destruct_n(buffer, domain_size); | type.destruct_n(buffer, domain_size); | ||||
| MEM_freeN(buffer); | MEM_freeN(buffer); | ||||
| return; | |||||
| } | } | ||||
| else { | } | ||||
| if (!attributes.add(name, domain, data_type, bke::AttributeInitMove{buffer})) { | |||||
| MEM_freeN(buffer); | if (attributes.remove(name)) { | ||||
| if (attributes.add(name, domain, data_type, bke::AttributeInitMove{buffer})) { | |||||
| return; | |||||
| } | } | ||||
| } | } | ||||
| /* If the name corresponds to a builtin attribute, removing the attribute might fail if | |||||
| * it's required, and adding the attribute might fail if the domain or type is incorrect. */ | |||||
| type.destruct_n(buffer, domain_size); | |||||
| MEM_freeN(buffer); | |||||
| failure = true; | |||||
| } | } | ||||
| static void node_geo_exec(GeoNodeExecParams params) | static void node_geo_exec(GeoNodeExecParams params) | ||||
| { | { | ||||
| GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); | GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); | ||||
| std::string name = params.extract_input<std::string>("Name"); | std::string name = params.extract_input<std::string>("Name"); | ||||
| if (name.empty()) { | if (name.empty()) { | ||||
| Show All 34 Lines | case CD_PROP_BOOL: | ||||
| break; | break; | ||||
| case CD_PROP_INT32: | case CD_PROP_INT32: | ||||
| field = params.get_input<Field<int>>("Value_Int"); | field = params.get_input<Field<int>>("Value_Int"); | ||||
| break; | break; | ||||
| default: | default: | ||||
| break; | break; | ||||
| } | } | ||||
| std::atomic<bool> failure = false; | |||||
| /* Run on the instances component separately to only affect the top level of instances. */ | /* Run on the instances component separately to only affect the top level of instances. */ | ||||
| if (domain == ATTR_DOMAIN_INSTANCE) { | if (domain == ATTR_DOMAIN_INSTANCE) { | ||||
| if (geometry_set.has_instances()) { | if (geometry_set.has_instances()) { | ||||
| GeometryComponent &component = geometry_set.get_component_for_write( | GeometryComponent &component = geometry_set.get_component_for_write( | ||||
| GEO_COMPONENT_TYPE_INSTANCES); | GEO_COMPONENT_TYPE_INSTANCES); | ||||
| try_capture_field_on_geometry(component, name, domain, field); | try_capture_field_on_geometry(component, name, domain, field, failure); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { | geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { | ||||
| for (const GeometryComponentType type : | for (const GeometryComponentType type : | ||||
| {GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}) { | {GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}) { | ||||
| if (geometry_set.has(type)) { | if (geometry_set.has(type)) { | ||||
| GeometryComponent &component = geometry_set.get_component_for_write(type); | GeometryComponent &component = geometry_set.get_component_for_write(type); | ||||
| try_capture_field_on_geometry(component, name, domain, field); | try_capture_field_on_geometry(component, name, domain, field, failure); | ||||
| } | } | ||||
| } | } | ||||
| }); | }); | ||||
| } | } | ||||
| if (failure) { | |||||
| const char *domain_name = nullptr; | |||||
| RNA_enum_name_from_value(rna_enum_attribute_domain_items, domain, &domain_name); | |||||
| const char *type_name = nullptr; | |||||
| RNA_enum_name_from_value(rna_enum_attribute_type_items, data_type, &type_name); | |||||
| char *message = BLI_sprintfN( | |||||
| TIP_("Failed to write to attribute \"%s\" with domain \"%s\" and type \"%s\""), | |||||
| name.c_str(), | |||||
| TIP_(domain_name), | |||||
| TIP_(type_name)); | |||||
| params.error_message_add(NodeWarningType::Warning, message); | |||||
| MEM_freeN(message); | |||||
| } | |||||
| params.set_output("Geometry", std::move(geometry_set)); | params.set_output("Geometry", std::move(geometry_set)); | ||||
| } | } | ||||
| } // namespace blender::nodes::node_geo_store_named_attribute_cc | } // namespace blender::nodes::node_geo_store_named_attribute_cc | ||||
| void register_node_type_geo_store_named_attribute() | void register_node_type_geo_store_named_attribute() | ||||
| { | { | ||||
| namespace file_ns = blender::nodes::node_geo_store_named_attribute_cc; | namespace file_ns = blender::nodes::node_geo_store_named_attribute_cc; | ||||
| Show All 17 Lines | |||||
Use r_ for output parameters.