Blender V5.0
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
8
10
11#include "BKE_attribute.hh"
12#include "BKE_attribute_math.hh"
13#include "BKE_context.hh"
15
16#include "WM_api.hh"
17#include "WM_types.hh"
18
19#include "ED_curves.hh"
20#include "ED_geometry.hh"
21#include "ED_object.hh"
22#include "ED_screen.hh"
23#include "ED_transform.hh"
24#include "ED_view3d.hh"
25
26#include "RNA_access.hh"
27
29#include "UI_resources.hh"
30
31#include "DNA_object_types.h"
32
33#include "DEG_depsgraph.hh"
34
35/* -------------------------------------------------------------------- */
38
39namespace blender::ed::curves {
40
42{
44 return false;
45 }
46 const Object *object = CTX_data_active_object(C);
47 const ID &object_data = *static_cast<const ID *>(object->data);
48 if (!geometry::attribute_set_poll(*C, object_data)) {
49 return false;
50 }
51 return true;
52}
53
55 const bke::AttrDomain domain,
56 IndexMaskMemory &memory)
57{
58 switch (domain) {
60 return retrieve_selected_points(curves_id, memory);
62 return retrieve_selected_curves(curves_id, memory);
63 default:
65 return {};
66 }
67}
68
69static void validate_value(const bke::AttributeAccessor attributes,
70 const StringRef name,
71 const CPPType &type,
72 void *buffer)
73{
74 const bke::AttributeValidator validator = attributes.lookup_validator(name);
75 if (!validator) {
76 return;
77 }
78 BUFFER_FOR_CPP_TYPE_VALUE(type, validated_buffer);
79 BLI_SCOPED_DEFER([&]() { type.destruct(validated_buffer); });
80
81 const IndexMask single_mask(1);
82 mf::ParamsBuilder params(*validator.function, &single_mask);
83 params.add_readonly_single_input(GPointer(type, buffer));
84 params.add_uninitialized_single_output({type, validated_buffer, 1});
85 mf::ContextBuilder context;
86 validator.function->call(single_mask, params, context);
87
88 type.copy_assign(validated_buffer, buffer);
89}
90
92{
93 Object *active_object = CTX_data_active_object(C);
94 Curves &active_curves_id = *static_cast<Curves *>(active_object->data);
95
96 AttributeOwner active_owner = AttributeOwner::from_id(&active_curves_id.id);
97 const StringRef name = *BKE_attributes_active_name_get(active_owner);
98 const bke::AttributeMetaData active_meta_data =
99 *active_curves_id.geometry.wrap().attributes().lookup_meta_data(name);
100 const bke::AttrType active_type = active_meta_data.data_type;
101 const CPPType &type = bke::attribute_type_to_cpp_type(active_type);
102
103 BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
104 BLI_SCOPED_DEFER([&]() { type.destruct(buffer); });
106 *op->ptr, active_type, buffer);
107
109
110 for (Curves *curves_id : get_unique_editable_curves(*C)) {
111 bke::CurvesGeometry &curves = curves_id->geometry.wrap();
112 bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
114 if (!attribute) {
115 continue;
116 }
117
118 /* Use implicit conversions to try to handle the case where the active attribute has a
119 * different type on multiple objects. */
120 const CPPType &dst_type = attribute.span.type();
121 if (&type != &dst_type && !conversions.is_convertible(type, dst_type)) {
122 continue;
123 }
124 BUFFER_FOR_CPP_TYPE_VALUE(dst_type, dst_buffer);
125 BLI_SCOPED_DEFER([&]() { dst_type.destruct(dst_buffer); });
126 conversions.convert_to_uninitialized(type, dst_type, value.get(), dst_buffer);
127
128 validate_value(attributes, name, dst_type, dst_buffer);
129 const GPointer dst_value(type, dst_buffer);
130
131 IndexMaskMemory memory;
132 const IndexMask selection = retrieve_selected_elements(*curves_id, attribute.domain, memory);
133 if (selection.is_empty()) {
134 attribute.finish();
135 continue;
136 }
137 dst_type.fill_assign_indices(dst_value.get(), attribute.span.data(), selection);
138 attribute.finish();
139
140 DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
141 WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id);
142 }
143
144 return OPERATOR_FINISHED;
145}
146
148{
149 Object *active_object = CTX_data_active_object(C);
150 Curves &active_curves_id = *static_cast<Curves *>(active_object->data);
151
152 AttributeOwner owner = AttributeOwner::from_id(&active_curves_id.id);
154 const bke::CurvesGeometry &curves = active_curves_id.geometry.wrap();
155 const bke::AttributeAccessor attributes = curves.attributes();
156 const bke::GAttributeReader attribute = attributes.lookup(name);
157 const bke::AttrDomain domain = attribute.domain;
158
159 IndexMaskMemory memory;
160 const IndexMask selection = retrieve_selected_elements(active_curves_id, domain, memory);
161
162 const CPPType &type = attribute.varray.type();
163
166 if (RNA_property_is_set(op->ptr, prop)) {
167 return WM_operator_props_popup(C, op, event);
168 }
169
170 BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
171 BLI_SCOPED_DEFER([&]() { type.destruct(buffer); });
172
173 bke::attribute_math::convert_to_static_type(type, [&](auto dummy) {
174 using T = decltype(dummy);
175 const VArray<T> values_typed = attribute.varray.typed<T>();
176 bke::attribute_math::DefaultMixer<T> mixer{MutableSpan(static_cast<T *>(buffer), 1)};
177 selection.foreach_index([&](const int i) { mixer.mix_in(0, values_typed[i]); });
178 mixer.finalize();
179 });
180
182
183 return WM_operator_props_popup(C, op, event);
184}
185
187{
188 uiLayout *layout = &op->layout->column(true);
189 layout->use_property_split_set(true);
190 layout->use_property_decorate_set(false);
191
193 Curves &curves_id = *static_cast<Curves *>(object->data);
194
195 AttributeOwner owner = AttributeOwner::from_id(&curves_id.id);
197 const bke::CurvesGeometry &curves = curves_id.geometry.wrap();
198 const bke::AttributeMetaData meta_data = *curves.attributes().lookup_meta_data(name);
200 layout->prop(op->ptr, prop_name, UI_ITEM_NONE, name, ICON_NONE);
201}
202
204{
205 using namespace blender::ed;
206 using namespace blender::ed::curves;
207 ot->name = "Set Attribute";
208 ot->description = "Set values of the active attribute for selected elements";
209 ot->idname = "CURVES_OT_attribute_set";
210
211 ot->exec = set_attribute_exec;
212 ot->invoke = set_attribute_invoke;
214 ot->ui = set_attribute_ui;
215
217
219}
220
221} // namespace blender::ed::curves
222
std::optional< blender::StringRefNull > BKE_attributes_active_name_get(AttributeOwner &owner)
Definition attribute.cc:784
Object * CTX_data_active_object(const bContext *C)
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#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:1074
Object is a sort of wrapper for general info.
@ OPERATOR_FINISHED
#define C
Definition RandGen.cpp:29
#define UI_ITEM_NONE
#define NC_GEOM
Definition WM_types.hh:393
#define ND_DATA
Definition WM_types.hh:509
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
static AttributeOwner from_id(ID *id)
Definition attribute.cc:44
static const CPPType & get()
void fill_assign_indices(const void *value, void *dst, const IndexMask &mask) const
void destruct(void *ptr) const
void copy_assign(const void *src, void *dst) const
const CPPType & type() const
const void * get() const
AttributeValidator lookup_validator(const StringRef attribute_id) const
GAttributeReader lookup(const StringRef attribute_id) const
std::optional< AttributeMetaData > lookup_meta_data(StringRef attribute_id) const
AttributeAccessor attributes() 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
GSpanAttributeWriter lookup_for_write_span(StringRef attribute_id)
virtual void call(const IndexMask &mask, Params params, Context context) const =0
void foreach_index(Fn &&fn) const
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
#define T
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
typename DefaultMixerStruct< T >::type DefaultMixer
const DataTypeConversions & get_implicit_type_conversions()
AttrType cpp_type_to_attribute_type(const CPPType &type)
const CPPType & attribute_type_to_cpp_type(AttrType type)
static IndexMask retrieve_selected_elements(const Curves &curves_id, const bke::AttrDomain domain, IndexMaskMemory &memory)
IndexMask retrieve_selected_curves(const bke::CurvesGeometry &curves, IndexMaskMemory &memory)
VectorSet< Curves * > get_unique_editable_curves(const bContext &C)
Definition curves_ops.cc:91
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 bool active_attribute_poll(bContext *C)
static void set_attribute_ui(bContext *C, wmOperator *op)
static wmOperatorStatus set_attribute_exec(bContext *C, wmOperator *op)
void CURVES_OT_attribute_set(wmOperatorType *ot)
static wmOperatorStatus set_attribute_invoke(bContext *C, wmOperator *op, const wmEvent *event)
IndexMask retrieve_selected_points(const bke::CurvesGeometry &curves, IndexMaskMemory &memory)
PropertyRNA * rna_property_for_type(PointerRNA &ptr, const bke::AttrType type)
GPointer rna_property_for_attribute_type_retrieve_value(PointerRNA &ptr, const bke::AttrType type, void *buffer)
StringRefNull rna_property_name_for_type(const bke::AttrType 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)
const char * name
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
CurvesGeometry geometry
Definition DNA_ID.h:414
const fn::multi_function::MultiFunction * function
void use_property_decorate_set(bool is_sep)
uiLayout & column(bool align)
void use_property_split_set(bool value)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
struct uiLayout * layout
struct PointerRNA * ptr
i
Definition text_draw.cc:230
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4237
wmOperatorStatus WM_operator_props_popup(bContext *C, wmOperator *op, const wmEvent *)