diff options
author | Jacques Lucke <jacques@blender.org> | 2021-01-14 17:55:51 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2021-01-14 17:55:51 +0300 |
commit | 9131c697ddda0ad640167d9f52e97bb697e187d0 (patch) | |
tree | c73ec2089ab6611569f849c07eb5ccd2cb009caf /source/blender | |
parent | 87955143845230919326914e5377f76ce231d306 (diff) | |
parent | e5ee7e9a2df93d7f28f9e1f8bc0eb2d33dfadfb4 (diff) |
Merge branch 'blender-v2.92-release'
Diffstat (limited to 'source/blender')
15 files changed, 260 insertions, 54 deletions
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index 9dc2b80d4d4..57fad6bcdf6 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -65,6 +65,62 @@ template<> struct DefaultHash<GeometryComponentType> { }; } // namespace blender +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. + */ +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); + + ~OutputAttributePtr(); + + /* Returns false, when this wrapper is empty. */ + operator bool() const + { + return static_cast<bool>(attribute_); + } + + /* Get a reference to the underlying #WriteAttribute. */ + blender::bke::WriteAttribute &get() + { + BLI_assert(attribute_); + return *attribute_; + } + + blender::bke::WriteAttribute &operator*() + { + return *attribute_; + } + + blender::bke::WriteAttribute *operator->() + { + return attribute_.get(); + } + + void save(); + void apply_span_and_save(); +}; + /** * This is the base class for specialized geometry component types. */ @@ -185,14 +241,17 @@ class GeometryComponent { } /** - * Returns the attribute with the given parameters if it exists. - * If an exact match does not exist, other attributes with the same name are deleted and a new - * attribute is created if possible. + * If an attribute with the given params exist, it is returned. + * If no attribute with the given name exists, it is created and returned. + * 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. */ - blender::bke::WriteAttributePtr attribute_try_ensure_for_write( - const blender::StringRef attribute_name, - const AttributeDomain domain, - const CustomDataType data_type); + OutputAttributePtr attribute_try_get_for_output(const blender::StringRef attribute_name, + const AttributeDomain domain, + const CustomDataType data_type); }; template<typename T> diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index 8d30bc95236..6739294a2c4 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -40,8 +40,10 @@ static CLG_LogRef LOG = {"bke.attribute_access"}; using blender::float3; using blender::Set; using blender::StringRef; +using blender::StringRefNull; using blender::bke::ReadAttributePtr; using blender::bke::WriteAttributePtr; +using blender::fn::GMutableSpan; /* Can't include BKE_object_deform.h right now, due to an enum forward declaration. */ extern "C" MDeformVert *BKE_object_defgroup_data_create(ID *id); @@ -250,6 +252,54 @@ template<typename T> class ArrayWriteAttribute final : public WriteAttribute { } }; +/* This is used by the #OutputAttributePtr class. */ +class TemporaryWriteAttribute final : public WriteAttribute { + public: + GMutableSpan data; + GeometryComponent &component; + std::string final_name; + + TemporaryWriteAttribute(AttributeDomain domain, + GMutableSpan data, + GeometryComponent &component, + std::string final_name) + : WriteAttribute(domain, data.type(), data.size()), + data(data), + component(component), + final_name(std::move(final_name)) + { + } + + ~TemporaryWriteAttribute() override + { + if (data.data() != nullptr) { + cpp_type_.destruct_n(data.data(), data.size()); + MEM_freeN(data.data()); + } + } + + void get_internal(const int64_t index, void *r_value) const override + { + data.type().copy_to_uninitialized(data[index], r_value); + } + + void set_internal(const int64_t index, const void *value) override + { + data.type().copy_to_initialized(value, data[index]); + } + + void initialize_span(const bool UNUSED(write_only)) override + { + array_buffer_ = data.data(); + array_is_temporary_ = false; + } + + void apply_span_if_necessary() override + { + /* Do nothing, because the span contains the attribute itself already. */ + } +}; + template<typename T> class ArrayReadAttribute final : public ReadAttribute { private: Span<T> data_; @@ -762,30 +812,117 @@ blender::bke::ReadAttributePtr GeometryComponent::attribute_get_constant_for_rea return attribute; } -WriteAttributePtr GeometryComponent::attribute_try_ensure_for_write(const StringRef attribute_name, - const AttributeDomain domain, - const CustomDataType data_type) +OutputAttributePtr GeometryComponent::attribute_try_get_for_output(const StringRef attribute_name, + const AttributeDomain domain, + const CustomDataType data_type) { + BLI_assert(this->attribute_domain_with_type_supported(domain, data_type)); + const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type); BLI_assert(cpp_type != nullptr); WriteAttributePtr attribute = this->attribute_try_get_for_write(attribute_name); - if (attribute && attribute->domain() == domain && attribute->cpp_type() == *cpp_type) { - return attribute; + + /* If the attribute doesn't exist, make a new one with the correct type. */ + if (!attribute) { + this->attribute_try_create(attribute_name, domain, data_type); + attribute = this->attribute_try_get_for_write(attribute_name); + return OutputAttributePtr(std::move(attribute)); } - if (attribute) { - if (!this->attribute_try_delete(attribute_name)) { - return {}; - } + /* If an existing attribute has a matching domain and type, just use that. */ + if (attribute->domain() == domain && attribute->cpp_type() == *cpp_type) { + return OutputAttributePtr(std::move(attribute)); } - if (!this->attribute_domain_with_type_supported(domain, data_type)) { - return {}; + + /* Otherwise create a temporary buffer to use before saving the new attribute. */ + return OutputAttributePtr(*this, domain, attribute_name, data_type); +} + +/* Construct from an attribute that already exists in the geometry component. */ +OutputAttributePtr::OutputAttributePtr(WriteAttributePtr attribute) + : attribute_(std::move(attribute)) +{ +} + +/* Construct a temporary attribute that has to replace an existing one later on. */ +OutputAttributePtr::OutputAttributePtr(GeometryComponent &component, + AttributeDomain domain, + std::string final_name, + CustomDataType data_type) +{ + const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type); + BLI_assert(cpp_type != nullptr); + + const int domain_size = component.attribute_domain_size(domain); + void *buffer = MEM_malloc_arrayN(domain_size, cpp_type->size(), __func__); + cpp_type->construct_default_n(buffer, domain_size); + + attribute_ = std::make_unique<blender::bke::TemporaryWriteAttribute>( + domain, GMutableSpan{*cpp_type, buffer, domain_size}, component, std::move(final_name)); +} + +/* Store the computed attribute. If it was stored from the beginning already, nothing is done. This + * might delete another attribute with the same name. */ +void OutputAttributePtr::save() +{ + if (!attribute_) { + CLOG_WARN(&LOG, "Trying to save an attribute that does not exist anymore."); + return; } - if (!this->attribute_try_create(attribute_name, domain, data_type)) { - return {}; + + blender::bke::TemporaryWriteAttribute *attribute = + dynamic_cast<blender::bke::TemporaryWriteAttribute *>(attribute_.get()); + + if (attribute == nullptr) { + /* The attribute is saved already. */ + attribute_.reset(); + return; } - return this->attribute_try_get_for_write(attribute_name); + + StringRefNull name = attribute->final_name; + const blender::fn::CPPType &cpp_type = attribute->cpp_type(); + + /* Delete an existing attribute with the same name if necessary. */ + attribute->component.attribute_try_delete(name); + + if (!attribute->component.attribute_try_create( + name, attribute_->domain(), attribute_->custom_data_type())) { + /* Cannot create the target attribute for some reason. */ + CLOG_WARN(&LOG, + "Creating the '%s' attribute with type '%s' failed.", + name.c_str(), + cpp_type.name().c_str()); + attribute_.reset(); + return; + } + + WriteAttributePtr new_attribute = attribute->component.attribute_try_get_for_write(name); + + GMutableSpan temp_span = attribute->data; + GMutableSpan new_span = new_attribute->get_span_for_write_only(); + BLI_assert(temp_span.size() == new_span.size()); + + /* Currently we copy over the attribute. In the future we want to reuse the buffer. */ + cpp_type.move_to_initialized_n(temp_span.data(), new_span.data(), new_span.size()); + new_attribute->apply_span(); + + attribute_.reset(); +} + +OutputAttributePtr::~OutputAttributePtr() +{ + if (attribute_) { + CLOG_ERROR(&LOG, "Forgot to call #save or #apply_span_and_save."); + } +} + +/* Utility function to call #apply_span and #save in the right order. */ +void OutputAttributePtr::apply_span_and_save() +{ + BLI_assert(attribute_); + attribute_->apply_span(); + this->save(); } /** \} */ diff --git a/source/blender/functions/FN_spans.hh b/source/blender/functions/FN_spans.hh index 2c1257f9ad2..41c930581a4 100644 --- a/source/blender/functions/FN_spans.hh +++ b/source/blender/functions/FN_spans.hh @@ -161,6 +161,14 @@ class GMutableSpan { void *operator[](int64_t index) { + BLI_assert(index >= 0); + BLI_assert(index < size_); + return POINTER_OFFSET(data_, type_->size() * index); + } + + void *operator[](int64_t index) const + { + BLI_assert(index >= 0); BLI_assert(index < size_); return POINTER_OFFSET(data_, type_->size() * index); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc b/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc index c38f54ce7f7..eac77b25bd6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc @@ -41,12 +41,12 @@ static void align_rotations_on_component(GeometryComponent &component, const NodeGeometryAlignRotationToVector &storage = *(const NodeGeometryAlignRotationToVector *) node.storage; - WriteAttributePtr rotation_attribute = component.attribute_try_ensure_for_write( + OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output( "rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3); if (!rotation_attribute) { return; } - MutableSpan<float3> rotations = rotation_attribute->get_span().typed<float3>(); + MutableSpan<float3> rotations = rotation_attribute->get_span<float3>(); FloatReadAttribute factors = params.get_input_attribute<float>( "Factor", component, ATTR_DOMAIN_POINT, 1.0f); @@ -85,7 +85,7 @@ static void align_rotations_on_component(GeometryComponent &component, rotations[i] = new_rotation; } - rotation_attribute->apply_span(); + rotation_attribute.apply_span_and_save(); } static void geo_node_align_rotation_to_vector_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc index 2aca9ed581c..9b0900e19ab 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc @@ -46,7 +46,7 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon /* Once we support more domains at the user level, we have to decide how the result domain is * chosen. */ const AttributeDomain result_domain = ATTR_DOMAIN_POINT; - WriteAttributePtr attribute_result = component.attribute_try_ensure_for_write( + OutputAttributePtr attribute_result = component.attribute_try_get_for_output( result_name, result_domain, result_type); if (!attribute_result) { return; @@ -64,7 +64,7 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon BKE_colorband_evaluate(color_ramp, data_in[i], data_out[i]); } - attribute_result->apply_span(); + attribute_result.apply_span_and_save(); } static void geo_node_attribute_color_ramp_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc index 8ea88e7153d..20a2b2127c2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc @@ -242,7 +242,7 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx /* Get result attribute first, in case it has to overwrite one of the existing attributes. */ const std::string result_name = params.get_input<std::string>("Result"); - WriteAttributePtr attribute_result = component.attribute_try_ensure_for_write( + OutputAttributePtr attribute_result = component.attribute_try_get_for_output( result_name, result_domain, result_type); if (!attribute_result) { return; @@ -260,8 +260,7 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx return; } - BooleanWriteAttribute attribute_result_bool = *attribute_result; - MutableSpan<bool> result_span = attribute_result_bool.get_span_for_write_only(); + MutableSpan<bool> result_span = attribute_result->get_span_for_write_only<bool>(); /* Use specific types for correct equality operations, but for other operations we use implicit * conversions and float comparison. In other words, the comparison is not element-wise. */ @@ -300,7 +299,7 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx do_math_operation(*attribute_a, *attribute_b, operation, result_span); } - attribute_result_bool.apply_span(); + attribute_result.apply_span_and_save(); } static void geo_node_attribute_compare_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc index 96685196917..9cec4070f89 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc @@ -68,7 +68,7 @@ static void fill_attribute(GeometryComponent &component, const GeoNodeExecParams return; } - WriteAttributePtr attribute = component.attribute_try_ensure_for_write( + OutputAttributePtr attribute = component.attribute_try_get_for_output( attribute_name, domain, data_type); if (!attribute) { return; @@ -79,33 +79,31 @@ static void fill_attribute(GeometryComponent &component, const GeoNodeExecParams const float value = params.get_input<float>("Value_001"); MutableSpan<float> attribute_span = attribute->get_span_for_write_only<float>(); attribute_span.fill(value); - attribute->apply_span(); break; } case CD_PROP_FLOAT3: { const float3 value = params.get_input<float3>("Value"); MutableSpan<float3> attribute_span = attribute->get_span_for_write_only<float3>(); attribute_span.fill(value); - attribute->apply_span(); break; } case CD_PROP_COLOR: { const Color4f value = params.get_input<Color4f>("Value_002"); MutableSpan<Color4f> attribute_span = attribute->get_span_for_write_only<Color4f>(); attribute_span.fill(value); - attribute->apply_span(); break; } case CD_PROP_BOOL: { const bool value = params.get_input<bool>("Value_003"); MutableSpan<bool> attribute_span = attribute->get_span_for_write_only<bool>(); attribute_span.fill(value); - attribute->apply_span(); break; } default: break; } + + attribute.apply_span_and_save(); } static void geo_node_attribute_fill_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc index 6e3b34f702a..f8ec9124db3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc @@ -107,7 +107,7 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP /* Get result attribute first, in case it has to overwrite one of the existing attributes. */ const std::string result_name = params.get_input<std::string>("Result"); - WriteAttributePtr attribute_result = component.attribute_try_ensure_for_write( + OutputAttributePtr attribute_result = component.attribute_try_get_for_output( result_name, result_domain, result_type); if (!attribute_result) { return; @@ -123,6 +123,7 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP } do_math_operation(*attribute_a, *attribute_b, *attribute_result, operation); + attribute_result.save(); } static void geo_node_attribute_math_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc index 4d8645b3b25..58d67145e75 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc @@ -136,7 +136,7 @@ static void attribute_mix_calc(GeometryComponent &component, const GeoNodeExecPa result_domain = result_attribute_read->domain(); } - WriteAttributePtr attribute_result = component.attribute_try_ensure_for_write( + OutputAttributePtr attribute_result = component.attribute_try_get_for_output( result_name, result_domain, result_type); if (!attribute_result) { return; @@ -155,6 +155,7 @@ static void attribute_mix_calc(GeometryComponent &component, const GeoNodeExecPa *attribute_a, *attribute_b, *attribute_result); + attribute_result.save(); } static void geo_node_attribute_mix_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc index 60e1441e363..0e7bb25e659 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc @@ -151,7 +151,7 @@ static void randomize_attribute(GeometryComponent &component, return; } - WriteAttributePtr attribute = component.attribute_try_ensure_for_write( + OutputAttributePtr attribute = component.attribute_try_get_for_output( attribute_name, domain, data_type); if (!attribute) { return; @@ -179,6 +179,8 @@ static void randomize_attribute(GeometryComponent &component, default: break; } + + attribute.save(); } static void geo_node_random_attribute_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc index de377e8bc87..529906a35e7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc @@ -345,7 +345,7 @@ static void attribute_vector_math_calc(GeometryComponent &component, /* Get result attribute first, in case it has to overwrite one of the existing attributes. */ const std::string result_name = params.get_input<std::string>("Result"); - WriteAttributePtr attribute_result = component.attribute_try_ensure_for_write( + OutputAttributePtr attribute_result = component.attribute_try_get_for_output( result_name, result_domain, result_type); if (!attribute_result) { return; @@ -390,6 +390,7 @@ static void attribute_vector_math_calc(GeometryComponent &component, *attribute_a, *attribute_b, *attribute_c, *attribute_result, operation); break; } + attribute_result.save(); } static void geo_node_attribute_vector_math_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc index 46b29a08feb..5e9b780db6d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc @@ -248,11 +248,11 @@ BLI_NOINLINE static void add_remaining_point_attributes(const Mesh &mesh, Span<float3> bary_coords, Span<int> looptri_indices) { - WriteAttributePtr id_attribute = component.attribute_try_ensure_for_write( + OutputAttributePtr id_attribute = component.attribute_try_get_for_output( "id", ATTR_DOMAIN_POINT, CD_PROP_INT32); - WriteAttributePtr normal_attribute = component.attribute_try_ensure_for_write( + OutputAttributePtr normal_attribute = component.attribute_try_get_for_output( "normal", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3); - WriteAttributePtr rotation_attribute = component.attribute_try_ensure_for_write( + OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output( "rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3); compute_special_attributes(mesh, @@ -262,9 +262,9 @@ BLI_NOINLINE static void add_remaining_point_attributes(const Mesh &mesh, id_attribute->get_span_for_write_only<int>(), rotation_attribute->get_span_for_write_only<float3>()); - id_attribute->apply_span(); - normal_attribute->apply_span(); - rotation_attribute->apply_span(); + id_attribute.apply_span_and_save(); + normal_attribute.apply_span_and_save(); + rotation_attribute.apply_span_and_save(); } static void sample_mesh_surface_with_minimum_distance(const Mesh &mesh, diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_rotate.cc b/source/blender/nodes/geometry/nodes/node_geo_point_rotate.cc index f22036ffe62..b1451dfb89e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_rotate.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_rotate.cc @@ -104,13 +104,13 @@ static void point_rotate_on_component(GeometryComponent &component, const bNode &node = params.node(); const NodeGeometryRotatePoints &storage = *(const NodeGeometryRotatePoints *)node.storage; - WriteAttributePtr rotation_attribute = component.attribute_try_ensure_for_write( + OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output( "rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3); if (!rotation_attribute) { return; } - MutableSpan<float3> rotations = rotation_attribute->get_span().typed<float3>(); + MutableSpan<float3> rotations = rotation_attribute->get_span<float3>(); const int domain_size = rotations.size(); if (storage.type == GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE) { @@ -138,7 +138,7 @@ static void point_rotate_on_component(GeometryComponent &component, } } - rotation_attribute->apply_span(); + rotation_attribute.apply_span_and_save(); } static void geo_node_point_rotate_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_scale.cc b/source/blender/nodes/geometry/nodes/node_geo_point_scale.cc index 165f467fef0..e5cbe27768d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_scale.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_scale.cc @@ -34,7 +34,7 @@ namespace blender::nodes { static void execute_on_component(GeoNodeExecParams params, GeometryComponent &component) { - Float3WriteAttribute scale_attribute = component.attribute_try_ensure_for_write( + OutputAttributePtr scale_attribute = component.attribute_try_get_for_output( "scale", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3); ReadAttributePtr attribute = params.get_input_attribute( "Factor", component, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, nullptr); @@ -43,12 +43,12 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co } Span<float3> data = attribute->get_span<float3>(); - MutableSpan<float3> scale_span = scale_attribute.get_span(); + MutableSpan<float3> scale_span = scale_attribute->get_span<float3>(); for (const int i : scale_span.index_range()) { scale_span[i] = scale_span[i] * data[i]; } - scale_attribute.apply_span(); + scale_attribute.apply_span_and_save(); } static void geo_node_point_scale_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc b/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc index 1dbc6016024..72176b11fdb 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc @@ -34,7 +34,7 @@ namespace blender::nodes { static void execute_on_component(GeoNodeExecParams params, GeometryComponent &component) { - Float3WriteAttribute position_attribute = component.attribute_try_ensure_for_write( + OutputAttributePtr position_attribute = component.attribute_try_get_for_output( "position", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3); ReadAttributePtr attribute = params.get_input_attribute( "Translation", component, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, nullptr); @@ -43,12 +43,12 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co } Span<float3> data = attribute->get_span<float3>(); - MutableSpan<float3> scale_span = position_attribute.get_span(); + MutableSpan<float3> scale_span = position_attribute->get_span<float3>(); for (const int i : scale_span.index_range()) { scale_span[i] = scale_span[i] + data[i]; } - position_attribute.apply_span(); + position_attribute.apply_span_and_save(); } static void geo_node_point_translate_exec(GeoNodeExecParams params) |