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
8
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/* -------------------------------------------------------------------- */
42
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();
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
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
214 ot->exec = set_attribute_exec;
215 ot->invoke = set_attribute_invoke;
217 ot->ui = set_attribute_ui;
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.
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color attribute
#define C
Definition RandGen.cpp:29
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)
#define NC_GEOM
Definition WM_types.hh:360
#define ND_DATA
Definition WM_types.hh:475
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
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
void copy_assign(const void *src, void *dst) const
const void * get() const
constexpr const char * c_str() const
AttributeValidator lookup_validator(const StringRef attribute_id) const
GAttributeReader lookup(const StringRef attribute_id) 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
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()
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)
GPU_SHADER_INTERFACE_INFO(overlay_edit_curve_handle_iface, "vert").flat(Type pos vertex_in(1, Type::UINT, "data") .vertex_out(overlay_edit_curve_handle_iface) .geometry_layout(PrimitiveIn Frequency::GEOMETRY storage_buf(1, Qualifier::READ, "uint", "data[]", Frequency::GEOMETRY) .push_constant(Type Frequency::GEOMETRY selection[]
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
CurvesGeometry geometry
Definition DNA_ID.h:413
const fn::multi_function::MultiFunction * function
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 *)