From 6da6b28084db31b9a9ebda0724bf18d85790ac1a Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 14 Feb 2023 23:19:49 -0500 Subject: [PATCH 1/5] Curves: Add edit mode operator to set attribute values Similar to the mesh edit mode operator with the same name TODO: Validation, cleanup --- release/scripts/startup/bl_ui/space_view3d.py | 1 + source/blender/editors/curves/CMakeLists.txt | 1 + .../editors/curves/intern/attribute_set.cc | 204 ++++++++++++++++++ .../editors/curves/intern/curves_ops.cc | 1 + .../editors/geometry/geometry_attributes.cc | 126 +++++++++++ source/blender/editors/include/ED_curves.h | 8 + source/blender/editors/include/ED_geometry.h | 18 ++ .../editors/mesh/editmesh_attribute.cc | 119 +--------- 8 files changed, 366 insertions(+), 112 deletions(-) create mode 100644 source/blender/editors/curves/intern/attribute_set.cc diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 9903ebc085b..60b5f26a42f 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -5311,6 +5311,7 @@ class VIEW3D_MT_edit_curves(Menu): layout.menu("VIEW3D_MT_transform") layout.separator() + layout.operator("curves.attribute_set") class VIEW3D_MT_object_mode_pie(Menu): diff --git a/source/blender/editors/curves/CMakeLists.txt b/source/blender/editors/curves/CMakeLists.txt index 873df89b40c..76e7786252f 100644 --- a/source/blender/editors/curves/CMakeLists.txt +++ b/source/blender/editors/curves/CMakeLists.txt @@ -21,6 +21,7 @@ set(INC ) set(SRC + intern/attribute_set.cc intern/curves_add.cc intern/curves_data.cc intern/curves_ops.cc diff --git a/source/blender/editors/curves/intern/attribute_set.cc b/source/blender/editors/curves/intern/attribute_set.cc new file mode 100644 index 00000000000..60c0f42830b --- /dev/null +++ b/source/blender/editors/curves/intern/attribute_set.cc @@ -0,0 +1,204 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup edmesh + */ + +#include "BLI_generic_pointer.hh" + +#include "BKE_attribute.h" +#include "BKE_attribute_math.hh" +#include "BKE_context.h" +#include "BKE_report.h" +#include "BKE_type_conversions.hh" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_curves.h" +#include "ED_geometry.h" +#include "ED_object.h" +#include "ED_screen.h" +#include "ED_transform.h" +#include "ED_view3d.h" + +#include "RNA_access.h" + +#include "BLT_translation.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "DNA_object_types.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +/* -------------------------------------------------------------------- */ +/** \name Delete Operator + * \{ */ + +namespace blender::ed::curves { + +static bool active_attribute_poll(bContext *C) +{ + if (!editable_curves_in_edit_mode_poll(C)) { + return false; + } + Object *object = CTX_data_active_object(C); + Curves &curves_id = *static_cast(object->data); + const CustomDataLayer *layer = BKE_id_attributes_active_get(&const_cast(curves_id.id)); + if (!layer) { + CTX_wm_operator_poll_msg_set(C, "No active attribute"); + return false; + } + if (layer->type == CD_PROP_STRING) { + CTX_wm_operator_poll_msg_set(C, "Active string attribute not supported"); + return false; + } + return true; +} + +static IndexMask retrieve_selected_elements(const Curves &curves_id, Vector &r_indices) +{ + switch (eAttrDomain(curves_id.selection_domain)) { + case ATTR_DOMAIN_POINT: + return retrieve_selected_points(curves_id, r_indices); + case ATTR_DOMAIN_CURVE: + return retrieve_selected_curves(curves_id, r_indices); + default: + BLI_assert_unreachable(); + return {}; + } +} + +static int set_attribute_exec(bContext *C, wmOperator *op) +{ + Object *active_object = CTX_data_active_object(C); + Curves &active_curves_id = *static_cast(active_object->data); + + CustomDataLayer *active_attribute = BKE_id_attributes_active_get(&active_curves_id.id); + const eCustomDataType active_type = eCustomDataType(active_attribute->type); + const CPPType &type = *bke::custom_data_type_to_cpp_type(active_type); + + BUFFER_FOR_CPP_TYPE_VALUE(type, buffer); + BLI_SCOPED_DEFER([&]() { type.destruct(buffer); }); + const GPointer value = geometry::rna_property_for_attribute_type_retrieve_value( + *op->ptr, active_type, buffer); + + const bke::DataTypeConversions &conversions = bke::get_implicit_type_conversions(); + + for (Curves *curves_id : get_unique_editable_curves(*C)) { + bke::CurvesGeometry &curves = curves_id->geometry.wrap(); + CustomDataLayer *layer = BKE_id_attributes_active_get(&curves_id->id); + if (!layer) { + continue; + } + bke::MutableAttributeAccessor attributes = curves.attributes_for_write(); + bke::GSpanAttributeWriter attribute = attributes.lookup_for_write_span(layer->name); + + /* Use implicit conversions to try to handle the case where the active attribute has a + * different type on multiple objects. */ + const CPPType &dst_type = attribute.span.type(); + if (&type != &dst_type && !conversions.is_convertible(type, dst_type)) { + continue; + } + BUFFER_FOR_CPP_TYPE_VALUE(dst_type, dst_buffer); + BLI_SCOPED_DEFER([&]() { dst_type.destruct(dst_buffer); }); + conversions.convert_to_uninitialized(type, dst_type, value.get(), dst_buffer); + const GPointer dst_value(dst_type, dst_buffer); + + const bke::AttributeValidator validator = attributes.lookup_validator(layer->name); + // validator.function->call() + + Vector indices; + const IndexMask selection = retrieve_selected_elements(*curves_id, indices); + if (selection.is_empty()) { + continue; + } + dst_type.fill_assign_indices(dst_value.get(), attribute.span.data(), selection); + attribute.finish(); + + DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id); + } + + return OPERATOR_FINISHED; +} + +static int set_attribute_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + Object *active_object = CTX_data_active_object(C); + Curves &active_curves_id = *static_cast(active_object->data); + + CustomDataLayer *active_attribute = BKE_id_attributes_active_get(&active_curves_id.id); + const bke::CurvesGeometry &curves = active_curves_id.geometry.wrap(); + const bke::AttributeAccessor attributes = curves.attributes(); + const bke::GAttributeReader attribute = attributes.lookup(active_attribute->name); + const eAttrDomain domain = attribute.domain; + const VArray selection = attributes.lookup_or_default(".selection", domain, true); + const CPPType &type = attribute.varray.type(); + + const StringRefNull prop_name = geometry::rna_property_name_for_type( + bke::cpp_type_to_custom_data_type(type)); + PropertyRNA *prop = RNA_struct_find_property(op->ptr, prop_name.c_str()); + if (RNA_property_is_set(op->ptr, prop)) { + return WM_operator_props_popup(C, op, event); + } + + BUFFER_FOR_CPP_TYPE_VALUE(type, buffer); + BLI_SCOPED_DEFER([&]() { type.destruct(buffer); }); + + attribute_math::convert_to_static_type(type, [&](auto dummy) { + using T = decltype(dummy); + const VArray values_typed = attribute.varray.typed(); + attribute_math::DefaultMixer mixer{MutableSpan(static_cast(buffer), 1)}; + for (const int i : values_typed.index_range()) { + if (selection[i]) { + mixer.mix_in(0, values_typed[i]); + } + } + }); + + geometry::rna_property_for_attribute_type_set_value(*op->ptr, *prop, GPointer(type, buffer)); + + return WM_operator_props_popup(C, op, event); +} + +static void set_attribute_ui(bContext *C, wmOperator *op) +{ + uiLayout *layout = uiLayoutColumn(op->layout, true); + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); + + Object *object = CTX_data_active_object(C); + Curves &curves_id = *static_cast(object->data); + + CustomDataLayer *active_attribute = BKE_id_attributes_active_get(&curves_id.id); + const eCustomDataType active_type = eCustomDataType(active_attribute->type); + const StringRefNull prop_name = geometry::rna_property_name_for_type(active_type); + const char *name = active_attribute->name; + uiItemR(layout, op->ptr, prop_name.c_str(), 0, name, ICON_NONE); +} + +void CURVES_OT_attribute_set(wmOperatorType *ot) +{ + using namespace blender::ed; + using namespace blender::ed::curves; + ot->name = "Set Attribute"; + ot->description = "Set values of the active attribute for selected elements"; + ot->idname = "CURVES_OT_attribute_set"; + + ot->exec = set_attribute_exec; + ot->invoke = set_attribute_invoke; + ot->poll = active_attribute_poll; + ot->ui = set_attribute_ui; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + geometry::register_rna_properties_for_attribute_types(*ot->srna); +} + +} // namespace blender::ed::curves + +/** \} */ diff --git a/source/blender/editors/curves/intern/curves_ops.cc b/source/blender/editors/curves/intern/curves_ops.cc index d80ebff2adc..dd0ed8f6a71 100644 --- a/source/blender/editors/curves/intern/curves_ops.cc +++ b/source/blender/editors/curves/intern/curves_ops.cc @@ -1096,6 +1096,7 @@ static void CURVES_OT_surface_set(wmOperatorType *ot) void ED_operatortypes_curves() { using namespace blender::ed::curves; + WM_operatortype_append(CURVES_OT_attribute_set); WM_operatortype_append(CURVES_OT_convert_to_particle_system); WM_operatortype_append(CURVES_OT_convert_from_particle_system); WM_operatortype_append(CURVES_OT_snap_curves_to_surface); diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc index 516d67220cb..ae5a56c7e14 100644 --- a/source/blender/editors/geometry/geometry_attributes.cc +++ b/source/blender/editors/geometry/geometry_attributes.cc @@ -41,6 +41,132 @@ namespace blender::ed::geometry { +StringRefNull rna_property_name_for_type(const eCustomDataType type) +{ + switch (type) { + case CD_PROP_FLOAT: + return "value_float"; + case CD_PROP_FLOAT2: + return "value_float_vector_2d"; + case CD_PROP_FLOAT3: + return "value_float_vector_3d"; + case CD_PROP_COLOR: + case CD_PROP_BYTE_COLOR: + return "value_color"; + case CD_PROP_BOOL: + return "value_bool"; + case CD_PROP_INT8: + case CD_PROP_INT32: + return "value_int"; + default: + BLI_assert_unreachable(); + return ""; + } +} + +void register_rna_properties_for_attribute_types(StructRNA &srna) +{ + static blender::float4 color_default(1); + + RNA_def_float(&srna, "value_float", 0.0f, -FLT_MAX, FLT_MAX, "Value", "", -FLT_MAX, FLT_MAX); + RNA_def_float_array(&srna, + "value_float_vector_2d", + 2, + nullptr, + -FLT_MAX, + FLT_MAX, + "Value", + "", + -FLT_MAX, + FLT_MAX); + RNA_def_float_array(&srna, + "value_float_vector_3d", + 3, + nullptr, + -FLT_MAX, + FLT_MAX, + "Value", + "", + -FLT_MAX, + FLT_MAX); + RNA_def_int(&srna, "value_int", 0, INT_MIN, INT_MAX, "Value", "", INT_MIN, INT_MAX); + RNA_def_float_color( + &srna, "value_color", 4, color_default, -FLT_MAX, FLT_MAX, "Value", "", 0.0f, 1.0f); + RNA_def_boolean(&srna, "value_bool", false, "Value", ""); +} + +GPointer rna_property_for_attribute_type_retrieve_value(PointerRNA &ptr, + const eCustomDataType type, + void *buffer) +{ + const StringRefNull prop_name = rna_property_name_for_type(type); + switch (type) { + case CD_PROP_FLOAT: + *static_cast(buffer) = RNA_float_get(&ptr, prop_name.c_str()); + break; + case CD_PROP_FLOAT2: + RNA_float_get_array(&ptr, prop_name.c_str(), static_cast(buffer)); + break; + case CD_PROP_FLOAT3: + RNA_float_get_array(&ptr, prop_name.c_str(), static_cast(buffer)); + break; + case CD_PROP_COLOR: + RNA_float_get_array(&ptr, prop_name.c_str(), static_cast(buffer)); + break; + case CD_PROP_BYTE_COLOR: + ColorGeometry4f value; + RNA_float_get_array(&ptr, prop_name.c_str(), value); + *static_cast(buffer) = value.encode(); + break; + case CD_PROP_BOOL: + *static_cast(buffer) = RNA_boolean_get(&ptr, prop_name.c_str()); + break; + case CD_PROP_INT8: + *static_cast(buffer) = RNA_int_get(&ptr, prop_name.c_str()); + break; + case CD_PROP_INT32: + *static_cast(buffer) = RNA_int_get(&ptr, prop_name.c_str()); + break; + default: + BLI_assert_unreachable(); + } + return GPointer(bke::custom_data_type_to_cpp_type(type), buffer); +} + +void rna_property_for_attribute_type_set_value(PointerRNA &ptr, + PropertyRNA &prop, + const GPointer value) +{ + switch (bke::cpp_type_to_custom_data_type(*value.type())) { + case CD_PROP_FLOAT: + RNA_property_float_set(&ptr, &prop, *value.get()); + break; + case CD_PROP_FLOAT2: + RNA_property_float_set_array(&ptr, &prop, *value.get()); + break; + case CD_PROP_FLOAT3: + RNA_property_float_set_array(&ptr, &prop, *value.get()); + break; + case CD_PROP_BYTE_COLOR: + RNA_property_float_set_array(&ptr, &prop, value.get()->decode()); + break; + case CD_PROP_COLOR: + RNA_property_float_set_array(&ptr, &prop, *value.get()); + break; + case CD_PROP_BOOL: + RNA_property_boolean_set(&ptr, &prop, *value.get()); + break; + case CD_PROP_INT8: + RNA_property_int_set(&ptr, &prop, *value.get()); + break; + case CD_PROP_INT32: + RNA_property_int_set(&ptr, &prop, *value.get()); + break; + default: + BLI_assert_unreachable(); + } +} + /*********************** Attribute Operators ************************/ static bool geometry_attributes_poll(bContext *C) diff --git a/source/blender/editors/include/ED_curves.h b/source/blender/editors/include/ED_curves.h index 2bfe99ea2bd..0ce68b37137 100644 --- a/source/blender/editors/include/ED_curves.h +++ b/source/blender/editors/include/ED_curves.h @@ -68,6 +68,14 @@ bool curves_poll(bContext *C); /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Operators + * \{ */ + +void CURVES_OT_attribute_set(wmOperatorType *ot); + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Selection * diff --git a/source/blender/editors/include/ED_geometry.h b/source/blender/editors/include/ED_geometry.h index 8436df73d10..0ad58971aba 100644 --- a/source/blender/editors/include/ED_geometry.h +++ b/source/blender/editors/include/ED_geometry.h @@ -10,6 +10,24 @@ #include "BKE_attribute.h" #include "DNA_customdata_types.h" +#ifdef __cplusplus + +# include "BLI_generic_pointer.hh" +# include "BLI_string_ref.hh" + +namespace blender::ed::geometry { + +StringRefNull rna_property_name_for_type(eCustomDataType type); +void register_rna_properties_for_attribute_types(StructRNA &srna); +GPointer rna_property_for_attribute_type_retrieve_value(PointerRNA &ptr, + const eCustomDataType type, + void *buffer); +void rna_property_for_attribute_type_set_value(PointerRNA &ptr, PropertyRNA &prop, GPointer value); + +} // namespace blender::ed::geometry + +#endif + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/editors/mesh/editmesh_attribute.cc b/source/blender/editors/mesh/editmesh_attribute.cc index 8594f3ebc1c..0f7a1ee39a0 100644 --- a/source/blender/editors/mesh/editmesh_attribute.cc +++ b/source/blender/editors/mesh/editmesh_attribute.cc @@ -22,6 +22,7 @@ #include "RNA_define.h" #include "RNA_enum_types.h" +#include "ED_geometry.h" #include "ED_mesh.h" #include "ED_object.h" #include "ED_screen.h" @@ -85,29 +86,6 @@ static bool mesh_active_attribute_poll(bContext *C) namespace set_attribute { -static StringRefNull rna_property_name_for_type(const eCustomDataType type) -{ - switch (type) { - case CD_PROP_FLOAT: - return "value_float"; - case CD_PROP_FLOAT2: - return "value_float_vector_2d"; - case CD_PROP_FLOAT3: - return "value_float_vector_3d"; - case CD_PROP_COLOR: - case CD_PROP_BYTE_COLOR: - return "value_color"; - case CD_PROP_BOOL: - return "value_bool"; - case CD_PROP_INT8: - case CD_PROP_INT32: - return "value_int"; - default: - BLI_assert_unreachable(); - return ""; - } -} - static void bmesh_vert_edge_face_layer_selected_values_set(BMesh &bm, const BMIterType iter_type, const GPointer value, @@ -179,39 +157,9 @@ static int mesh_set_attribute_exec(bContext *C, wmOperator *op) BUFFER_FOR_CPP_TYPE_VALUE(type, buffer); BLI_SCOPED_DEFER([&]() { type.destruct(buffer); }); + const GPointer value = geometry::rna_property_for_attribute_type_retrieve_value( + *op->ptr, active_type, buffer); - const StringRefNull prop_name = rna_property_name_for_type(active_type); - switch (active_type) { - case CD_PROP_FLOAT: - *static_cast(buffer) = RNA_float_get(op->ptr, prop_name.c_str()); - break; - case CD_PROP_FLOAT2: - RNA_float_get_array(op->ptr, prop_name.c_str(), static_cast(buffer)); - break; - case CD_PROP_FLOAT3: - RNA_float_get_array(op->ptr, prop_name.c_str(), static_cast(buffer)); - break; - case CD_PROP_COLOR: - RNA_float_get_array(op->ptr, prop_name.c_str(), static_cast(buffer)); - break; - case CD_PROP_BYTE_COLOR: - ColorGeometry4f value; - RNA_float_get_array(op->ptr, prop_name.c_str(), value); - *static_cast(buffer) = value.encode(); - break; - case CD_PROP_BOOL: - *static_cast(buffer) = RNA_boolean_get(op->ptr, prop_name.c_str()); - break; - case CD_PROP_INT8: - *static_cast(buffer) = RNA_int_get(op->ptr, prop_name.c_str()); - break; - case CD_PROP_INT32: - *static_cast(buffer) = RNA_int_get(op->ptr, prop_name.c_str()); - break; - default: - BLI_assert_unreachable(); - } - const GPointer value(type, buffer); const bke::DataTypeConversions &conversions = bke::get_implicit_type_conversions(); bool changed = false; @@ -289,40 +237,13 @@ static int mesh_set_attribute_invoke(bContext *C, wmOperator *op, const wmEvent return WM_operator_props_popup(C, op, event); } - const StringRefNull prop_name = rna_property_name_for_type(data_type); + const StringRefNull prop_name = geometry::rna_property_name_for_type(data_type); const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type); const GPointer active_value(type, POINTER_OFFSET(active_elem->head.data, layer->offset)); PropertyRNA *prop = RNA_struct_find_property(op->ptr, prop_name.c_str()); if (!RNA_property_is_set(op->ptr, prop)) { - switch (data_type) { - case CD_PROP_FLOAT: - RNA_property_float_set(op->ptr, prop, *active_value.get()); - break; - case CD_PROP_FLOAT2: - RNA_property_float_set_array(op->ptr, prop, *active_value.get()); - break; - case CD_PROP_FLOAT3: - RNA_property_float_set_array(op->ptr, prop, *active_value.get()); - break; - case CD_PROP_BYTE_COLOR: - RNA_property_float_set_array(op->ptr, prop, active_value.get()->decode()); - break; - case CD_PROP_COLOR: - RNA_property_float_set_array(op->ptr, prop, *active_value.get()); - break; - case CD_PROP_BOOL: - RNA_property_boolean_set(op->ptr, prop, *active_value.get()); - break; - case CD_PROP_INT8: - RNA_property_int_set(op->ptr, prop, *active_value.get()); - break; - case CD_PROP_INT32: - RNA_property_int_set(op->ptr, prop, *active_value.get()); - break; - default: - BLI_assert_unreachable(); - } + geometry::rna_property_for_attribute_type_set_value(*op->ptr, *prop, active_value); } return WM_operator_props_popup(C, op, event); @@ -337,7 +258,7 @@ static void mesh_set_attribute_ui(bContext *C, wmOperator *op) Mesh *mesh = ED_mesh_context(C); CustomDataLayer *active_attribute = BKE_id_attributes_active_get(&mesh->id); const eCustomDataType active_type = eCustomDataType(active_attribute->type); - const StringRefNull prop_name = rna_property_name_for_type(active_type); + const StringRefNull prop_name = geometry::rna_property_name_for_type(active_type); const char *name = active_attribute->name; uiItemR(layout, op->ptr, prop_name.c_str(), 0, name, ICON_NONE); } @@ -361,33 +282,7 @@ void MESH_OT_attribute_set(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - static blender::float4 color_default(1); - - RNA_def_float(ot->srna, "value_float", 0.0f, -FLT_MAX, FLT_MAX, "Value", "", -FLT_MAX, FLT_MAX); - RNA_def_float_array(ot->srna, - "value_float_vector_2d", - 2, - nullptr, - -FLT_MAX, - FLT_MAX, - "Value", - "", - -FLT_MAX, - FLT_MAX); - RNA_def_float_array(ot->srna, - "value_float_vector_3d", - 3, - nullptr, - -FLT_MAX, - FLT_MAX, - "Value", - "", - -FLT_MAX, - FLT_MAX); - RNA_def_int(ot->srna, "value_int", 0, INT_MIN, INT_MAX, "Value", "", INT_MIN, INT_MAX); - RNA_def_float_color( - ot->srna, "value_color", 4, color_default, -FLT_MAX, FLT_MAX, "Value", "", 0.0f, 1.0f); - RNA_def_boolean(ot->srna, "value_bool", false, "Value", ""); + blender::ed::geometry::register_rna_properties_for_attribute_types(*ot->srna); } /** \} */ -- 2.30.2 From 0812374525be2c10b063ca44d6d5f9dffdb104aa Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 22 Feb 2023 09:01:55 -0500 Subject: [PATCH 2/5] Add validation, add comments, small cleanup --- .../editors/curves/intern/attribute_set.cc | 39 ++++++++++++++----- .../editors/geometry/geometry_attributes.cc | 5 +++ source/blender/editors/include/ED_geometry.h | 13 +++++++ .../editors/mesh/editmesh_attribute.cc | 3 +- 4 files changed, 49 insertions(+), 11 deletions(-) diff --git a/source/blender/editors/curves/intern/attribute_set.cc b/source/blender/editors/curves/intern/attribute_set.cc index 60c0f42830b..f762be872cf 100644 --- a/source/blender/editors/curves/intern/attribute_set.cc +++ b/source/blender/editors/curves/intern/attribute_set.cc @@ -59,9 +59,11 @@ static bool active_attribute_poll(bContext *C) return true; } -static IndexMask retrieve_selected_elements(const Curves &curves_id, Vector &r_indices) +static IndexMask retrieve_selected_elements(const Curves &curves_id, + const eAttrDomain domain, + Vector &r_indices) { - switch (eAttrDomain(curves_id.selection_domain)) { + switch (domain) { case ATTR_DOMAIN_POINT: return retrieve_selected_points(curves_id, r_indices); case ATTR_DOMAIN_CURVE: @@ -72,6 +74,27 @@ static IndexMask retrieve_selected_elements(const Curves &curves_id, Vectorcall(IndexMask(1), params, context); + + type.copy_assign(validated_buffer, buffer); +} + static int set_attribute_exec(bContext *C, wmOperator *op) { Object *active_object = CTX_data_active_object(C); @@ -106,13 +129,12 @@ static int set_attribute_exec(bContext *C, wmOperator *op) BUFFER_FOR_CPP_TYPE_VALUE(dst_type, dst_buffer); BLI_SCOPED_DEFER([&]() { dst_type.destruct(dst_buffer); }); conversions.convert_to_uninitialized(type, dst_type, value.get(), dst_buffer); - const GPointer dst_value(dst_type, dst_buffer); - const bke::AttributeValidator validator = attributes.lookup_validator(layer->name); - // validator.function->call() + validate_value(attributes, layer->name, dst_type, dst_buffer); + const GPointer dst_value(type, dst_buffer); Vector indices; - const IndexMask selection = retrieve_selected_elements(*curves_id, indices); + const IndexMask selection = retrieve_selected_elements(*curves_id, attribute.domain, indices); if (selection.is_empty()) { continue; } @@ -139,9 +161,8 @@ static int set_attribute_invoke(bContext *C, wmOperator *op, const wmEvent *even const VArray selection = attributes.lookup_or_default(".selection", domain, true); const CPPType &type = attribute.varray.type(); - const StringRefNull prop_name = geometry::rna_property_name_for_type( - bke::cpp_type_to_custom_data_type(type)); - PropertyRNA *prop = RNA_struct_find_property(op->ptr, prop_name.c_str()); + PropertyRNA *prop = geometry::rna_property_for_type(*op->ptr, + bke::cpp_type_to_custom_data_type(type)); if (RNA_property_is_set(op->ptr, prop)) { return WM_operator_props_popup(C, op, event); } diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc index ae5a56c7e14..b32b897763e 100644 --- a/source/blender/editors/geometry/geometry_attributes.cc +++ b/source/blender/editors/geometry/geometry_attributes.cc @@ -64,6 +64,11 @@ StringRefNull rna_property_name_for_type(const eCustomDataType type) } } +PropertyRNA *rna_property_for_type(PointerRNA &ptr, const eCustomDataType type) +{ + return RNA_struct_find_property(&ptr, rna_property_name_for_type(type).c_str()); +} + void register_rna_properties_for_attribute_types(StructRNA &srna) { static blender::float4 color_default(1); diff --git a/source/blender/editors/include/ED_geometry.h b/source/blender/editors/include/ED_geometry.h index 0ad58971aba..4f499e37c32 100644 --- a/source/blender/editors/include/ED_geometry.h +++ b/source/blender/editors/include/ED_geometry.h @@ -15,15 +15,28 @@ # include "BLI_generic_pointer.hh" # include "BLI_string_ref.hh" +struct PointerRNA; +struct PropertyRNA; + namespace blender::ed::geometry { +/* -------------------------------------------------------------------- */ +/** \name Attribute Value RNA Property Helpers + * + * Functions to make it easier to register RNA properties for the various attribute types and + * retrieve/set their values. + * \{ */ + StringRefNull rna_property_name_for_type(eCustomDataType type); +PropertyRNA *rna_property_for_type(PointerRNA &ptr, const eCustomDataType type); void register_rna_properties_for_attribute_types(StructRNA &srna); GPointer rna_property_for_attribute_type_retrieve_value(PointerRNA &ptr, const eCustomDataType type, void *buffer); void rna_property_for_attribute_type_set_value(PointerRNA &ptr, PropertyRNA &prop, GPointer value); +/** \} */ + } // namespace blender::ed::geometry #endif diff --git a/source/blender/editors/mesh/editmesh_attribute.cc b/source/blender/editors/mesh/editmesh_attribute.cc index 0f7a1ee39a0..64467d79b8c 100644 --- a/source/blender/editors/mesh/editmesh_attribute.cc +++ b/source/blender/editors/mesh/editmesh_attribute.cc @@ -237,11 +237,10 @@ static int mesh_set_attribute_invoke(bContext *C, wmOperator *op, const wmEvent return WM_operator_props_popup(C, op, event); } - const StringRefNull prop_name = geometry::rna_property_name_for_type(data_type); const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type); const GPointer active_value(type, POINTER_OFFSET(active_elem->head.data, layer->offset)); - PropertyRNA *prop = RNA_struct_find_property(op->ptr, prop_name.c_str()); + PropertyRNA *prop = geometry::rna_property_for_type(*op->ptr, data_type); if (!RNA_property_is_set(op->ptr, prop)) { geometry::rna_property_for_attribute_type_set_value(*op->ptr, *prop, active_value); } -- 2.30.2 From ca2c7e2770f248785f327f30a714067f529b1978 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 22 Feb 2023 17:50:39 -0500 Subject: [PATCH 3/5] Fix mixing of existing values --- source/blender/editors/curves/intern/attribute_set.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/editors/curves/intern/attribute_set.cc b/source/blender/editors/curves/intern/attribute_set.cc index f762be872cf..936cfaff10f 100644 --- a/source/blender/editors/curves/intern/attribute_set.cc +++ b/source/blender/editors/curves/intern/attribute_set.cc @@ -179,6 +179,7 @@ static int set_attribute_invoke(bContext *C, wmOperator *op, const wmEvent *even mixer.mix_in(0, values_typed[i]); } } + mixer.finalize(); }); geometry::rna_property_for_attribute_type_set_value(*op->ptr, *prop, GPointer(type, buffer)); -- 2.30.2 From 134da4d97e6e7ec551488105368e2b3144dc6c6e Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 7 Mar 2023 12:20:03 -0500 Subject: [PATCH 4/5] Fix missing attribute finish() call --- source/blender/editors/curves/intern/attribute_set.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/editors/curves/intern/attribute_set.cc b/source/blender/editors/curves/intern/attribute_set.cc index 936cfaff10f..2c27624a62e 100644 --- a/source/blender/editors/curves/intern/attribute_set.cc +++ b/source/blender/editors/curves/intern/attribute_set.cc @@ -136,6 +136,7 @@ static int set_attribute_exec(bContext *C, wmOperator *op) Vector indices; const IndexMask selection = retrieve_selected_elements(*curves_id, attribute.domain, indices); if (selection.is_empty()) { + attribute.finish(); continue; } dst_type.fill_assign_indices(dst_value.get(), attribute.span.data(), selection); -- 2.30.2 From b78928438bc943dcfb3b02b564d9466be13d8676 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 17 Oct 2023 09:51:00 +0200 Subject: [PATCH 5/5] Build fixes and retrieve average value with same selection interpolation --- .../editors/curves/intern/attribute_set.cc | 58 +++++++++---------- .../editors/geometry/geometry_attributes.cc | 2 + source/blender/editors/include/ED_curves.hh | 1 + .../editors/mesh/editmesh_attribute.cc | 7 +-- 4 files changed, 33 insertions(+), 35 deletions(-) diff --git a/source/blender/editors/curves/intern/attribute_set.cc b/source/blender/editors/curves/intern/attribute_set.cc index 2c27624a62e..84e9524d4b7 100644 --- a/source/blender/editors/curves/intern/attribute_set.cc +++ b/source/blender/editors/curves/intern/attribute_set.cc @@ -12,27 +12,27 @@ #include "BKE_report.h" #include "BKE_type_conversions.hh" -#include "WM_api.h" -#include "WM_types.h" +#include "WM_api.hh" +#include "WM_types.hh" -#include "ED_curves.h" -#include "ED_geometry.h" -#include "ED_object.h" -#include "ED_screen.h" -#include "ED_transform.h" -#include "ED_view3d.h" +#include "ED_curves.hh" +#include "ED_geometry.hh" +#include "ED_object.hh" +#include "ED_screen.hh" +#include "ED_transform.hh" +#include "ED_view3d.hh" -#include "RNA_access.h" +#include "RNA_access.hh" #include "BLT_translation.h" -#include "UI_interface.h" -#include "UI_resources.h" +#include "UI_interface.hh" +#include "UI_resources.hh" #include "DNA_object_types.h" -#include "DEG_depsgraph.h" -#include "DEG_depsgraph_query.h" +#include "DEG_depsgraph.hh" +#include "DEG_depsgraph_query.hh" /* -------------------------------------------------------------------- */ /** \name Delete Operator @@ -61,13 +61,13 @@ static bool active_attribute_poll(bContext *C) static IndexMask retrieve_selected_elements(const Curves &curves_id, const eAttrDomain domain, - Vector &r_indices) + IndexMaskMemory &memory) { switch (domain) { case ATTR_DOMAIN_POINT: - return retrieve_selected_points(curves_id, r_indices); + return retrieve_selected_points(curves_id, memory); case ATTR_DOMAIN_CURVE: - return retrieve_selected_curves(curves_id, r_indices); + return retrieve_selected_curves(curves_id, memory); default: BLI_assert_unreachable(); return {}; @@ -86,11 +86,12 @@ static void validate_value(const bke::AttributeAccessor attributes, BUFFER_FOR_CPP_TYPE_VALUE(type, validated_buffer); BLI_SCOPED_DEFER([&]() { type.destruct(validated_buffer); }); - mf::ParamsBuilder params(*validator.function, 1); + const IndexMask single_mask(1); + mf::ParamsBuilder params(*validator.function, &single_mask); params.add_readonly_single_input(GPointer(type, buffer)); params.add_uninitialized_single_output({type, validated_buffer, 1}); mf::ContextBuilder context; - validator.function->call(IndexMask(1), params, context); + validator.function->call(single_mask, params, context); type.copy_assign(validated_buffer, buffer); } @@ -133,8 +134,8 @@ static int set_attribute_exec(bContext *C, wmOperator *op) validate_value(attributes, layer->name, dst_type, dst_buffer); const GPointer dst_value(type, dst_buffer); - Vector indices; - const IndexMask selection = retrieve_selected_elements(*curves_id, attribute.domain, indices); + IndexMaskMemory memory; + const IndexMask selection = retrieve_selected_elements(*curves_id, attribute.domain, memory); if (selection.is_empty()) { attribute.finish(); continue; @@ -159,7 +160,10 @@ static int set_attribute_invoke(bContext *C, wmOperator *op, const wmEvent *even const bke::AttributeAccessor attributes = curves.attributes(); const bke::GAttributeReader attribute = attributes.lookup(active_attribute->name); const eAttrDomain domain = attribute.domain; - const VArray selection = attributes.lookup_or_default(".selection", domain, true); + + IndexMaskMemory memory; + const IndexMask selection = retrieve_selected_elements(active_curves_id, domain, memory); + const CPPType &type = attribute.varray.type(); PropertyRNA *prop = geometry::rna_property_for_type(*op->ptr, @@ -171,15 +175,11 @@ static int set_attribute_invoke(bContext *C, wmOperator *op, const wmEvent *even BUFFER_FOR_CPP_TYPE_VALUE(type, buffer); BLI_SCOPED_DEFER([&]() { type.destruct(buffer); }); - attribute_math::convert_to_static_type(type, [&](auto dummy) { + bke::attribute_math::convert_to_static_type(type, [&](auto dummy) { using T = decltype(dummy); const VArray values_typed = attribute.varray.typed(); - attribute_math::DefaultMixer mixer{MutableSpan(static_cast(buffer), 1)}; - for (const int i : values_typed.index_range()) { - if (selection[i]) { - mixer.mix_in(0, values_typed[i]); - } - } + bke::attribute_math::DefaultMixer mixer{MutableSpan(static_cast(buffer), 1)}; + selection.foreach_index([&](const int i) { mixer.mix_in(0, values_typed[i]); }); mixer.finalize(); }); @@ -201,7 +201,7 @@ static void set_attribute_ui(bContext *C, wmOperator *op) const eCustomDataType active_type = eCustomDataType(active_attribute->type); const StringRefNull prop_name = geometry::rna_property_name_for_type(active_type); const char *name = active_attribute->name; - uiItemR(layout, op->ptr, prop_name.c_str(), 0, name, ICON_NONE); + uiItemR(layout, op->ptr, prop_name.c_str(), UI_ITEM_NONE, name, ICON_NONE); } void CURVES_OT_attribute_set(wmOperatorType *ot) diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc index 87386aa75ee..708403ab679 100644 --- a/source/blender/editors/geometry/geometry_attributes.cc +++ b/source/blender/editors/geometry/geometry_attributes.cc @@ -12,6 +12,8 @@ #include "DNA_meshdata_types.h" #include "DNA_scene_types.h" +#include "BLI_color.hh" + #include "BKE_attribute.h" #include "BKE_context.h" #include "BKE_deform.h" diff --git a/source/blender/editors/include/ED_curves.hh b/source/blender/editors/include/ED_curves.hh index 4ffd5cb61c9..1606baa5f31 100644 --- a/source/blender/editors/include/ED_curves.hh +++ b/source/blender/editors/include/ED_curves.hh @@ -105,6 +105,7 @@ IndexMask random_mask(const bke::CurvesGeometry &curves, eAttrDomain selection_domain, uint32_t random_seed, float probability, + IndexMaskMemory &memory); /** \} */ diff --git a/source/blender/editors/mesh/editmesh_attribute.cc b/source/blender/editors/mesh/editmesh_attribute.cc index 0427c99812a..1e676712f47 100644 --- a/source/blender/editors/mesh/editmesh_attribute.cc +++ b/source/blender/editors/mesh/editmesh_attribute.cc @@ -25,16 +25,11 @@ #include "RNA_define.hh" #include "RNA_enum_types.hh" -#include "ED_geometry.h" -#include "ED_mesh.h" +#include "ED_geometry.hh" #include "ED_mesh.hh" -#include "ED_object.h" #include "ED_object.hh" -#include "ED_screen.h" #include "ED_screen.hh" -#include "ED_transform.h" #include "ED_transform.hh" -#include "ED_view3d.h" #include "ED_view3d.hh" #include "BLT_translation.h" -- 2.30.2