Blender V4.3
curves_attribute_set.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include "BKE_attribute.hh"
12#include "BKE_attribute_math.hh"
13#include "BKE_context.hh"
14#include "BKE_report.hh"
16
17#include "WM_api.hh"
18#include "WM_types.hh"
19
20#include "ED_curves.hh"
21#include "ED_geometry.hh"
22#include "ED_object.hh"
23#include "ED_screen.hh"
24#include "ED_transform.hh"
25#include "ED_view3d.hh"
26
27#include "RNA_access.hh"
28
29#include "BLT_translation.hh"
30
31#include "UI_interface.hh"
32#include "UI_resources.hh"
33
34#include "DNA_object_types.h"
35
36#include "DEG_depsgraph.hh"
38
39/* -------------------------------------------------------------------- */
43namespace blender::ed::curves {
44
46{
48 return false;
49 }
50 const Object *object = CTX_data_active_object(C);
51 const ID &object_data = *static_cast<const ID *>(object->data);
52 if (!geometry::attribute_set_poll(*C, object_data)) {
53 return false;
54 }
55 return true;
56}
57
59 const bke::AttrDomain domain,
60 IndexMaskMemory &memory)
61{
62 switch (domain) {
64 return retrieve_selected_points(curves_id, memory);
66 return retrieve_selected_curves(curves_id, memory);
67 default:
69 return {};
70 }
71}
72
73static void validate_value(const bke::AttributeAccessor attributes,
74 const StringRef name,
75 const CPPType &type,
76 void *buffer)
77{
78 const bke::AttributeValidator validator = attributes.lookup_validator(name);
79 if (!validator) {
80 return;
81 }
82 BUFFER_FOR_CPP_TYPE_VALUE(type, validated_buffer);
83 BLI_SCOPED_DEFER([&]() { type.destruct(validated_buffer); });
84
85 const IndexMask single_mask(1);
86 mf::ParamsBuilder params(*validator.function, &single_mask);
87 params.add_readonly_single_input(GPointer(type, buffer));
88 params.add_uninitialized_single_output({type, validated_buffer, 1});
89 mf::ContextBuilder context;
90 validator.function->call(single_mask, params, context);
91
92 type.copy_assign(validated_buffer, buffer);
93}
94
96{
97 Object *active_object = CTX_data_active_object(C);
98 Curves &active_curves_id = *static_cast<Curves *>(active_object->data);
99
100 AttributeOwner owner = AttributeOwner::from_id(&active_curves_id.id);
101 CustomDataLayer *active_attribute = BKE_attributes_active_get(owner);
102 const eCustomDataType active_type = eCustomDataType(active_attribute->type);
103 const CPPType &type = *bke::custom_data_type_to_cpp_type(active_type);
104
105 BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
106 BLI_SCOPED_DEFER([&]() { type.destruct(buffer); });
108 *op->ptr, active_type, buffer);
109
111
112 for (Curves *curves_id : get_unique_editable_curves(*C)) {
113 bke::CurvesGeometry &curves = curves_id->geometry.wrap();
115 if (!layer) {
116 continue;
117 }
118 bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
119 bke::GSpanAttributeWriter attribute = attributes.lookup_for_write_span(layer->name);
120
121 /* Use implicit conversions to try to handle the case where the active attribute has a
122 * different type on multiple objects. */
123 const CPPType &dst_type = attribute.span.type();
124 if (&type != &dst_type && !conversions.is_convertible(type, dst_type)) {
125 continue;
126 }
127 BUFFER_FOR_CPP_TYPE_VALUE(dst_type, dst_buffer);
128 BLI_SCOPED_DEFER([&]() { dst_type.destruct(dst_buffer); });
129 conversions.convert_to_uninitialized(type, dst_type, value.get(), dst_buffer);
130
131 validate_value(attributes, layer->name, dst_type, dst_buffer);
132 const GPointer dst_value(type, dst_buffer);
133
134 IndexMaskMemory memory;
135 const IndexMask selection = retrieve_selected_elements(*curves_id, attribute.domain, memory);
136 if (selection.is_empty()) {
137 attribute.finish();
138 continue;
139 }
140 dst_type.fill_assign_indices(dst_value.get(), attribute.span.data(), selection);
141 attribute.finish();
142
143 DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
144 WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id);
145 }
146
147 return OPERATOR_FINISHED;
148}
149
150static int set_attribute_invoke(bContext *C, wmOperator *op, const wmEvent *event)
151{
152 Object *active_object = CTX_data_active_object(C);
153 Curves &active_curves_id = *static_cast<Curves *>(active_object->data);
154
155 AttributeOwner owner = AttributeOwner::from_id(&active_curves_id.id);
156 CustomDataLayer *active_attribute = BKE_attributes_active_get(owner);
157 const bke::CurvesGeometry &curves = active_curves_id.geometry.wrap();
158 const bke::AttributeAccessor attributes = curves.attributes();
159 const bke::GAttributeReader attribute = attributes.lookup(active_attribute->name);
160 const bke::AttrDomain domain = attribute.domain;
161
162 IndexMaskMemory memory;
163 const IndexMask selection = retrieve_selected_elements(active_curves_id, domain, memory);
164
165 const CPPType &type = attribute.varray.type();
166
169 if (RNA_property_is_set(op->ptr, prop)) {
170 return WM_operator_props_popup(C, op, event);
171 }
172
173 BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
174 BLI_SCOPED_DEFER([&]() { type.destruct(buffer); });
175
176 bke::attribute_math::convert_to_static_type(type, [&](auto dummy) {
177 using T = decltype(dummy);
178 const VArray<T> values_typed = attribute.varray.typed<T>();
179 bke::attribute_math::DefaultMixer<T> mixer{MutableSpan(static_cast<T *>(buffer), 1)};
180 selection.foreach_index([&](const int i) { mixer.mix_in(0, values_typed[i]); });
181 mixer.finalize();
182 });
183
185
186 return WM_operator_props_popup(C, op, event);
187}
188
190{
191 uiLayout *layout = uiLayoutColumn(op->layout, true);
192 uiLayoutSetPropSep(layout, true);
193 uiLayoutSetPropDecorate(layout, false);
194
195 Object *object = CTX_data_active_object(C);
196 Curves &curves_id = *static_cast<Curves *>(object->data);
197
198 AttributeOwner owner = AttributeOwner::from_id(&curves_id.id);
199 CustomDataLayer *active_attribute = BKE_attributes_active_get(owner);
200 const eCustomDataType active_type = eCustomDataType(active_attribute->type);
201 const StringRefNull prop_name = geometry::rna_property_name_for_type(active_type);
202 const char *name = active_attribute->name;
203 uiItemR(layout, op->ptr, prop_name.c_str(), UI_ITEM_NONE, name, ICON_NONE);
204}
205
207{
208 using namespace blender::ed;
209 using namespace blender::ed::curves;
210 ot->name = "Set Attribute";
211 ot->description = "Set values of the active attribute for selected elements";
212 ot->idname = "CURVES_OT_attribute_set";
213
218
220
222}
223
224} // namespace blender::ed::curves
225
struct CustomDataLayer * BKE_attributes_active_get(AttributeOwner &owner)
Definition attribute.cc:781
Object * CTX_data_active_object(const bContext *C)
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BUFFER_FOR_CPP_TYPE_VALUE(type, variable_name)
#define BLI_SCOPED_DEFER(function_to_defer)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
Object is a sort of wrapper for general info.
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define NC_GEOM
Definition WM_types.hh:360
#define ND_DATA
Definition WM_types.hh:475
static AttributeOwner from_id(ID *id)
Definition attribute.cc:43
void fill_assign_indices(const void *value, void *dst, const IndexMask &mask) const
static const CPPType & get()
void destruct(void *ptr) const
const void * get() const
constexpr const char * c_str() const
void convert_to_uninitialized(const CPPType &from_type, const CPPType &to_type, const void *from_value, void *to_value) const
bool is_convertible(const CPPType &from_type, const CPPType &to_type) const
virtual void call(const IndexMask &mask, Params params, Context context) const =0
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
typename DefaultMixerStruct< T >::type DefaultMixer
const DataTypeConversions & get_implicit_type_conversions()
eCustomDataType cpp_type_to_custom_data_type(const CPPType &type)
const CPPType * custom_data_type_to_cpp_type(eCustomDataType type)
static IndexMask retrieve_selected_elements(const Curves &curves_id, const bke::AttrDomain domain, IndexMaskMemory &memory)
static int set_attribute_invoke(bContext *C, wmOperator *op, const wmEvent *event)
IndexMask retrieve_selected_curves(const bke::CurvesGeometry &curves, IndexMaskMemory &memory)
VectorSet< Curves * > get_unique_editable_curves(const bContext &C)
Definition curves_ops.cc:96
static void validate_value(const bke::AttributeAccessor attributes, const StringRef name, const CPPType &type, void *buffer)
bool editable_curves_in_edit_mode_poll(bContext *C)
static int set_attribute_exec(bContext *C, wmOperator *op)
static bool active_attribute_poll(bContext *C)
static void set_attribute_ui(bContext *C, wmOperator *op)
void CURVES_OT_attribute_set(wmOperatorType *ot)
IndexMask retrieve_selected_points(const bke::CurvesGeometry &curves, IndexMaskMemory &memory)
GPointer rna_property_for_attribute_type_retrieve_value(PointerRNA &ptr, const eCustomDataType type, void *buffer)
StringRefNull rna_property_name_for_type(const eCustomDataType type)
void register_rna_properties_for_attribute_types(StructRNA &srna)
void rna_property_for_attribute_type_set_value(PointerRNA &ptr, PropertyRNA &prop, const GPointer value)
bool attribute_set_poll(bContext &C, const ID &object_data)
PropertyRNA * rna_property_for_type(PointerRNA &ptr, const eCustomDataType type)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
CurvesGeometry geometry
Definition DNA_ID.h:413
const fn::multi_function::MultiFunction * function
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
void(* ui)(bContext *C, wmOperator *op)
Definition WM_types.hh:1053
StructRNA * srna
Definition WM_types.hh:1080
struct uiLayout * layout
struct PointerRNA * ptr
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4125
int WM_operator_props_popup(bContext *C, wmOperator *op, const wmEvent *)