Blender V5.0
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_pointcloud.hh"
16
17#include "WM_api.hh"
18#include "WM_types.hh"
19
20#include "ED_geometry.hh"
21#include "ED_object.hh"
22#include "ED_pointcloud.hh"
23#include "ED_screen.hh"
24#include "ED_transform.hh"
25#include "ED_view3d.hh"
26
27#include "RNA_access.hh"
28
30#include "UI_resources.hh"
31
32#include "DNA_object_types.h"
33
34#include "FN_multi_function.hh"
35
36#include "DEG_depsgraph.hh"
37
38/* -------------------------------------------------------------------- */
41
43
45{
47 return false;
48 }
49 const Object *object = CTX_data_active_object(C);
50 const ID &object_data = *static_cast<const ID *>(object->data);
51 if (!geometry::attribute_set_poll(*C, object_data)) {
52 return false;
53 }
54 return true;
55}
56
57static void validate_value(const bke::AttributeAccessor attributes,
58 const StringRef name,
59 const CPPType &type,
60 void *buffer)
61{
62 const bke::AttributeValidator validator = attributes.lookup_validator(name);
63 if (!validator) {
64 return;
65 }
66 BUFFER_FOR_CPP_TYPE_VALUE(type, validated_buffer);
67 BLI_SCOPED_DEFER([&]() { type.destruct(validated_buffer); });
68
69 const IndexMask single_mask(1);
70 mf::ParamsBuilder params(*validator.function, &single_mask);
71 params.add_readonly_single_input(GPointer(type, buffer));
72 params.add_uninitialized_single_output({type, validated_buffer, 1});
73 mf::ContextBuilder context;
74 validator.function->call(single_mask, params, context);
75
76 type.copy_assign(validated_buffer, buffer);
77}
78
80{
81 Object *active_object = CTX_data_active_object(C);
82 PointCloud &active_pointcloud = *static_cast<PointCloud *>(active_object->data);
83
84 AttributeOwner active_owner = AttributeOwner::from_id(&active_pointcloud.id);
85 const StringRef name = *BKE_attributes_active_name_get(active_owner);
86 const bke::AttributeMetaData meta_data = *active_pointcloud.attributes().lookup_meta_data(name);
87 const bke::AttrType active_type = meta_data.data_type;
88 const CPPType &type = bke::attribute_type_to_cpp_type(active_type);
89
90 BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
91 BLI_SCOPED_DEFER([&]() { type.destruct(buffer); });
93 *op->ptr, active_type, buffer);
94
96
98 bke::MutableAttributeAccessor attributes = pointcloud->attributes_for_write();
100 if (!attribute) {
101 continue;
102 }
103
104 /* Use implicit conversions to try to handle the case where the active attribute has a
105 * different type on multiple objects. */
106 const CPPType &dst_type = attribute.span.type();
107 if (&type != &dst_type && !conversions.is_convertible(type, dst_type)) {
108 continue;
109 }
110 BUFFER_FOR_CPP_TYPE_VALUE(dst_type, dst_buffer);
111 BLI_SCOPED_DEFER([&]() { dst_type.destruct(dst_buffer); });
112 conversions.convert_to_uninitialized(type, dst_type, value.get(), dst_buffer);
113
114 validate_value(attributes, name, dst_type, dst_buffer);
115 const GPointer dst_value(type, dst_buffer);
116
117 IndexMaskMemory memory;
118 const IndexMask selection = retrieve_selected_points(*pointcloud, memory);
119 if (selection.is_empty()) {
120 attribute.finish();
121 continue;
122 }
123 dst_type.fill_assign_indices(dst_value.get(), attribute.span.data(), selection);
124 attribute.finish();
125
128 }
129
130 return OPERATOR_FINISHED;
131}
132
134{
135 Object *active_object = CTX_data_active_object(C);
136 PointCloud &active_pointcloud = *static_cast<PointCloud *>(active_object->data);
137
138 AttributeOwner owner = AttributeOwner::from_id(&active_pointcloud.id);
139 const bke::AttributeAccessor attributes = active_pointcloud.attributes();
141 const bke::GAttributeReader attribute = attributes.lookup(name);
142
143 IndexMaskMemory memory;
144 const IndexMask selection = retrieve_selected_points(active_pointcloud, memory);
145
146 const CPPType &type = attribute.varray.type();
147
150 if (RNA_property_is_set(op->ptr, prop)) {
151 return WM_operator_props_popup(C, op, event);
152 }
153
154 BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
155 BLI_SCOPED_DEFER([&]() { type.destruct(buffer); });
156
157 bke::attribute_math::convert_to_static_type(type, [&](auto dummy) {
158 using T = decltype(dummy);
159 const VArray<T> values_typed = attribute.varray.typed<T>();
160 bke::attribute_math::DefaultMixer<T> mixer{MutableSpan(static_cast<T *>(buffer), 1)};
161 selection.foreach_index([&](const int i) { mixer.mix_in(0, values_typed[i]); });
162 mixer.finalize();
163 });
164
166
167 return WM_operator_props_popup(C, op, event);
168}
169
171{
172 uiLayout *layout = &op->layout->column(true);
173 layout->use_property_split_set(true);
174 layout->use_property_decorate_set(false);
175
177 PointCloud &pointcloud = *static_cast<PointCloud *>(object->data);
178
181 const bke::AttributeMetaData meta_data = *pointcloud.attributes().lookup_meta_data(name);
183 layout->prop(op->ptr, prop_name, UI_ITEM_NONE, name, ICON_NONE);
184}
185
187{
188 ot->name = "Set Attribute";
189 ot->description = "Set values of the active attribute for selected elements";
190 ot->idname = "POINTCLOUD_OT_attribute_set";
191
192 ot->exec = set_attribute_exec;
193 ot->invoke = set_attribute_invoke;
195 ot->ui = set_attribute_ui;
196
198
200}
201
202} // namespace blender::ed::pointcloud
203
std::optional< blender::StringRefNull > BKE_attributes_active_name_get(AttributeOwner &owner)
Definition attribute.cc:784
Object * CTX_data_active_object(const bContext *C)
General operations for point clouds.
#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
AttributeSet attributes
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
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)
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)
bool editable_pointcloud_in_edit_mode_poll(bContext *C)
Definition operators.cc:73
static void validate_value(const bke::AttributeAccessor attributes, const StringRef name, const CPPType &type, void *buffer)
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)
static wmOperatorStatus set_attribute_invoke(bContext *C, wmOperator *op, const wmEvent *event)
IndexMask retrieve_selected_points(const PointCloud &pointcloud, IndexMaskMemory &memory)
Definition selection.cc:279
void POINTCLOUD_OT_attribute_set(wmOperatorType *ot)
VectorSet< PointCloud * > get_unique_editable_pointclouds(const bContext &C)
Definition operators.cc:78
const char * name
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
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 *)