Blender V5.0
node_geo_tool_set_selection.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
5#include "BKE_mesh.hh"
7
8#include "NOD_rna_define.hh"
9
11#include "UI_resources.hh"
12
13#include "RNA_enum_types.hh"
14
16
18
19#include "node_geometry_util.hh"
20
22
24enum class SelectionType {
26 Float = 1,
27};
28
30{
31 b.use_custom_socket_order();
32 b.allow_any_socket_order();
33 b.add_default_layout();
34 b.add_input<decl::Geometry>("Geometry").description("Geometry to update the selection of");
35 b.add_output<decl::Geometry>("Geometry").align_with_previous();
36 if (const bNode *node = b.node_or_null()) {
37 switch (SelectionType(node->custom2)) {
39 b.add_input<decl::Bool>("Selection").default_value(true).field_on_all();
40 break;
42 b.add_input<decl::Float>("Selection").default_value(1.0f).field_on_all();
43 break;
44 }
45 }
46}
47
48static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
49{
50 layout->prop(ptr, "domain", UI_ITEM_NONE, "", ICON_NONE);
51 layout->prop(ptr, "selection_type", UI_ITEM_NONE, "", ICON_NONE);
52}
53
54static void node_init(bNodeTree * /*tree*/, bNode *node)
55{
56 node->custom1 = int16_t(AttrDomain::Point);
57 node->custom2 = int16_t(SelectionType::Boolean);
58}
59
60static GField clamp_selection(const GField &selection)
61{
62 if (selection.cpp_type().is<bool>()) {
63 return selection;
64 }
65 static auto clamp = mf::build::SI1_SO<float, float>(
66 "Clamp", [](const float value) { return std::clamp(value, 0.0f, 1.0f); });
67 return Field<float>(FieldOperation::from(clamp, {selection}));
68}
69
70static GField invert_selection(const GField &selection)
71{
72 if (selection.cpp_type().is<bool>()) {
73 static auto invert = mf::build::SI1_SO<bool, bool>("Invert Selection",
74 [](const bool value) { return !value; });
75 return GField(FieldOperation::from(invert, {selection}));
76 }
77
78 static auto invert = mf::build::SI1_SO<float, float>(
79 "Invert Selection", [](const float value) { return 1.0f - value; });
80 return GField(FieldOperation::from(invert, {selection}));
81}
82
89 const StringRef name,
90 const bke::AttrDomain domain)
91{
92 if (const std::optional<bke::AttributeMetaData> meta_data = attributes.lookup_meta_data(name)) {
93 if (meta_data->domain != domain) {
94 attributes.remove(name);
95 }
96 }
97}
98
100{
102 return;
103 }
104 GeometrySet geometry = params.extract_input<GeometrySet>("Geometry");
105 const eObjectMode mode = params.user_data()->call_data->operator_data->mode;
107 params.error_message_add(NodeWarningType::Error,
108 "Selection control is not supported in this mode");
109 params.set_output("Geometry", std::move(geometry));
110 return;
111 }
112
113 const GField selection = params.extract_input<GField>("Selection");
114 const AttrDomain domain = AttrDomain(params.node().custom1);
117 if (Mesh *mesh = geometry.get_mesh_for_write()) {
118 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
119 remove_with_wrong_domain(attributes, ".select_vert", AttrDomain::Point);
120 remove_with_wrong_domain(attributes, ".select_edge", AttrDomain::Edge);
121 remove_with_wrong_domain(attributes, ".select_poly", AttrDomain::Face);
122 switch (mode) {
123 case OB_MODE_EDIT: {
124 const Field<bool> field = conversions.try_convert(selection, CPPType::get<bool>());
125 switch (domain) {
126 case AttrDomain::Point:
128 ".select_vert",
129 AttrDomain::Point,
130 field);
132 break;
133 case AttrDomain::Edge:
135 ".select_edge",
136 AttrDomain::Edge,
137 field);
139 break;
140 case AttrDomain::Face:
142 ".select_poly",
143 AttrDomain::Face,
144 field);
146 break;
147 default: {
148 break;
149 }
150 }
151 break;
152 }
153 case OB_MODE_SCULPT: {
154 GField on_domain = GField(
155 std::make_shared<bke::EvaluateOnDomainInput>(selection, domain));
156 GField clamped_and_inverted = invert_selection(clamp_selection(std::move(on_domain)));
157 const Field<float> field = conversions.try_convert(std::move(clamped_and_inverted),
160 ".sculpt_mask",
161 AttrDomain::Point,
162 field);
163 break;
164 }
165 default: {
166 break;
167 }
168 }
169 }
170 if (geometry.has_curves()) {
171 const GField field = clamp_selection(selection);
172 if (ELEM(domain, AttrDomain::Point, AttrDomain::Curve)) {
174 geometry.get_component_for_write<CurveComponent>(), ".selection", domain, field);
175 }
176 }
177 if (geometry.has_pointcloud()) {
178 const GField field = clamp_selection(selection);
179 if (domain == AttrDomain::Point) {
181 geometry.get_component_for_write<PointCloudComponent>(), ".selection", domain, field);
182 }
183 }
184 if (geometry.has_grease_pencil()) {
185 /* Grease Pencil only supports boolean selection. */
186 const Field<bool> field = conversions.try_convert(selection, CPPType::get<bool>());
187 if (ELEM(domain, AttrDomain::Point, AttrDomain::Curve)) {
189 geometry.get_component_for_write<GreasePencilComponent>(),
190 ".selection",
191 domain,
192 field);
193 }
194 }
195 });
196 params.set_output("Geometry", std::move(geometry));
197}
198
199static void node_rna(StructRNA *srna)
200{
202 "domain",
203 "Domain",
204 "",
207 int(AttrDomain::Point));
208 static EnumPropertyItem mode_items[] = {
210 "BOOLEAN",
211 0,
212 "Boolean",
213 "Store true or false selection values in edit mode"},
215 "FLOAT",
216 0,
217 "Float",
218 "Store floating point selection values. For mesh geometry, stored inverted as the sculpt "
219 "mode mask"},
220 {0, nullptr, 0, nullptr, nullptr},
221 };
223 "selection_type",
224 "Selection Type",
225 "",
226 mode_items,
229}
230
231static void node_register()
232{
233 static blender::bke::bNodeType ntype;
234 geo_node_type_base(&ntype, "GeometryNodeToolSetSelection", GEO_NODE_TOOL_SET_SELECTION);
235 ntype.ui_name = "Set Selection";
236 ntype.ui_description = "Set selection of the edited geometry, for tool execution";
237 ntype.enum_name_legacy = "TOOL_SELECTION_SET";
239 ntype.declare = node_declare;
240 ntype.initfunc = node_init;
245
246 node_rna(ntype.rna_ext.srna);
247}
249
250} // namespace blender::nodes::node_geo_tool_set_selection_cc
#define NODE_CLASS_GEOMETRY
Definition BKE_node.hh:461
#define GEO_NODE_TOOL_SET_SELECTION
#define ELEM(...)
eObjectMode
@ OB_MODE_EDIT
@ OB_MODE_SCULPT
@ OB_MODE_PAINT_GREASE_PENCIL
@ OB_MODE_OBJECT
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define NOD_inline_enum_accessors(member)
#define UI_ITEM_NONE
static const CPPType & get()
bool is() const
std::optional< AttributeMetaData > lookup_meta_data(StringRef attribute_id) const
GVArray try_convert(GVArray varray, const CPPType &to_type) const
bool remove(const StringRef attribute_id)
const CPPType & cpp_type() const
Definition FN_field.hh:130
static std::shared_ptr< FieldOperation > from(std::shared_ptr< const mf::MultiFunction > function, Vector< GField > inputs={})
Definition FN_field.hh:242
constexpr T clamp(T, U, U) RET
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
CCL_NAMESPACE_BEGIN ccl_device float invert(const float color, const float factor)
Definition invert.h:11
void mesh_select_vert_flush(Mesh &mesh)
const DataTypeConversions & get_implicit_type_conversions()
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
void mesh_select_edge_flush(Mesh &mesh)
bool try_capture_field_on_geometry(MutableAttributeAccessor attributes, const fn::FieldContext &field_context, const StringRef attribute_id, AttrDomain domain, const fn::Field< bool > &selection, const fn::GField &field)
void mesh_select_face_flush(Mesh &mesh)
void foreach_real_geometry(bke::GeometrySet &geometry, FunctionRef< void(bke::GeometrySet &geometry_set)> fn)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
static void node_declare(NodeDeclarationBuilder &b)
static void remove_with_wrong_domain(bke::MutableAttributeAccessor attributes, const StringRef name, const bke::AttrDomain domain)
static GField invert_selection(const GField &selection)
static GField clamp_selection(const GField &selection)
void search_link_ops_for_tool_node(GatherLinkSearchOpParams &params)
PropertyRNA * RNA_def_node_enum(StructRNA *srna, const char *identifier, const char *ui_name, const char *ui_description, const EnumPropertyItem *static_items, const EnumRNAAccessors accessors, std::optional< int > default_value, const EnumPropertyItemFunc item_func, const bool allow_animation)
bool check_tool_context_and_error(GeoNodeExecParams &params)
void geo_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
const char * name
const EnumPropertyItem rna_enum_attribute_domain_point_edge_face_curve_items[]
StructRNA * srna
int16_t custom1
int16_t custom2
Defines a node type.
Definition BKE_node.hh:238
std::string ui_description
Definition BKE_node.hh:244
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:289
NodeGeometryExecFunction geometry_node_execute
Definition BKE_node.hh:354
const char * enum_name_legacy
Definition BKE_node.hh:247
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:259
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
Definition BKE_node.hh:378
NodeDeclareFunction declare
Definition BKE_node.hh:362
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)
PointerRNA * ptr
Definition wm_files.cc:4238