diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index 7cdb190a66a..9b963d1820a 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -5823,6 +5823,7 @@ class VIEW3D_MT_edit_curves(Menu): layout.menu("VIEW3D_MT_transform") layout.separator() + layout.operator("curves.attribute_set") layout.operator("curves.delete") layout.template_node_operator_asset_menu_items(catalog_path=self.bl_label) diff --git a/source/blender/editors/curves/CMakeLists.txt b/source/blender/editors/curves/CMakeLists.txt index d5fcf758a33..ed4e3e98ea1 100644 --- a/source/blender/editors/curves/CMakeLists.txt +++ b/source/blender/editors/curves/CMakeLists.txt @@ -23,6 +23,7 @@ set(INC_SYS ) set(SRC + intern/attribute_set.cc intern/curves_add.cc intern/curves_data.cc intern/curves_edit.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..84e9524d4b7 --- /dev/null +++ b/source/blender/editors/curves/intern/attribute_set.cc @@ -0,0 +1,227 @@ +/* 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.hh" +#include "WM_types.hh" + +#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.hh" + +#include "BLT_translation.h" + +#include "UI_interface.hh" +#include "UI_resources.hh" + +#include "DNA_object_types.h" + +#include "DEG_depsgraph.hh" +#include "DEG_depsgraph_query.hh" + +/* -------------------------------------------------------------------- */ +/** \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, + const eAttrDomain domain, + IndexMaskMemory &memory) +{ + switch (domain) { + case ATTR_DOMAIN_POINT: + return retrieve_selected_points(curves_id, memory); + case ATTR_DOMAIN_CURVE: + return retrieve_selected_curves(curves_id, memory); + default: + BLI_assert_unreachable(); + return {}; + } +} + +static void validate_value(const bke::AttributeAccessor attributes, + const StringRef name, + const CPPType &type, + void *buffer) +{ + const bke::AttributeValidator validator = attributes.lookup_validator(name); + if (!validator) { + return; + } + BUFFER_FOR_CPP_TYPE_VALUE(type, validated_buffer); + BLI_SCOPED_DEFER([&]() { type.destruct(validated_buffer); }); + + 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(single_mask, 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); + 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); + + validate_value(attributes, layer->name, dst_type, dst_buffer); + const GPointer dst_value(type, dst_buffer); + + IndexMaskMemory memory; + const IndexMask selection = retrieve_selected_elements(*curves_id, attribute.domain, memory); + if (selection.is_empty()) { + attribute.finish(); + 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; + + 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, + bke::cpp_type_to_custom_data_type(type)); + 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); }); + + bke::attribute_math::convert_to_static_type(type, [&](auto dummy) { + using T = decltype(dummy); + const VArray values_typed = attribute.varray.typed(); + 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(); + }); + + 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(), UI_ITEM_NONE, 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 e37af75f360..637a82b0318 100644 --- a/source/blender/editors/curves/intern/curves_ops.cc +++ b/source/blender/editors/curves/intern/curves_ops.cc @@ -1236,6 +1236,7 @@ static void CURVES_OT_delete(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 f01385f219a..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" @@ -42,6 +44,137 @@ 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 ""; + } +} + +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); + + 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.hh b/source/blender/editors/include/ED_curves.hh index 524c54dcc83..1606baa5f31 100644 --- a/source/blender/editors/include/ED_curves.hh +++ b/source/blender/editors/include/ED_curves.hh @@ -70,6 +70,14 @@ bool curves_poll(bContext *C); /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Operators + * \{ */ + +void CURVES_OT_attribute_set(wmOperatorType *ot); + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Mask Functions * \{ */ diff --git a/source/blender/editors/include/ED_geometry.hh b/source/blender/editors/include/ED_geometry.hh index fb9ebb256f6..72172d50f3c 100644 --- a/source/blender/editors/include/ED_geometry.hh +++ b/source/blender/editors/include/ED_geometry.hh @@ -18,6 +18,33 @@ struct Mesh; struct ReportList; +#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 + void ED_operatortypes_geometry(); /** diff --git a/source/blender/editors/mesh/editmesh_attribute.cc b/source/blender/editors/mesh/editmesh_attribute.cc index 09e5d981781..1e676712f47 100644 --- a/source/blender/editors/mesh/editmesh_attribute.cc +++ b/source/blender/editors/mesh/editmesh_attribute.cc @@ -25,6 +25,7 @@ #include "RNA_define.hh" #include "RNA_enum_types.hh" +#include "ED_geometry.hh" #include "ED_mesh.hh" #include "ED_object.hh" #include "ED_screen.hh" @@ -88,33 +89,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"; - case CD_PROP_INT32_2D: - return "value_int_vector_2d"; - case CD_PROP_QUATERNION: - return "value_quat"; - default: - BLI_assert_unreachable(); - return ""; - } -} - static void bmesh_vert_edge_face_layer_selected_values_set(BMesh &bm, const BMIterType iter_type, const GPointer value, @@ -186,48 +160,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_QUATERNION: { - float4 value; - RNA_float_get_array(op->ptr, prop_name.c_str(), value); - *static_cast(buffer) = math::normalize(math::Quaternion(value)); - 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; - case CD_PROP_INT32_2D: - RNA_int_get_array(op->ptr, prop_name.c_str(), static_cast(buffer)); - break; - default: - BLI_assert_unreachable(); - } - const GPointer value(type, buffer); const bke::DataTypeConversions &conversions = bke::get_implicit_type_conversions(); bool changed = false; @@ -305,48 +240,12 @@ 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 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)) { - 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; - case CD_PROP_INT32_2D: - RNA_property_int_set_array(op->ptr, prop, *active_value.get()); - break; - case CD_PROP_QUATERNION: { - const math::Quaternion value = math::normalize(*active_value.get()); - RNA_property_float_set_array(op->ptr, prop, float4(value)); - 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); @@ -361,7 +260,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(), UI_ITEM_NONE, name, ICON_NONE); } @@ -385,53 +284,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_int_array(ot->srna, - "value_int_vector_2d", - 2, - nullptr, - 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", ""); - RNA_def_float_array(ot->srna, - "value_quat", - 4, - rna_default_quaternion, - -FLT_MAX, - FLT_MAX, - "Value", - "", - FLT_MAX, - FLT_MAX); + blender::ed::geometry::register_rna_properties_for_attribute_types(*ot->srna); } /** \} */