Blender V4.5
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
10#include "UI_interface.hh"
11#include "UI_resources.hh"
12
13#include "RNA_enum_types.hh"
14
16
17#include "node_geometry_util.hh"
18
20
22enum class SelectionType {
24 Float = 1,
25};
26
28{
29 b.use_custom_socket_order();
30 b.allow_any_socket_order();
31 b.add_default_layout();
32 b.add_input<decl::Geometry>("Geometry");
33 b.add_output<decl::Geometry>("Geometry").align_with_previous();
34 if (const bNode *node = b.node_or_null()) {
35 switch (SelectionType(node->custom2)) {
37 b.add_input<decl::Bool>("Selection").default_value(true).field_on_all();
38 break;
40 b.add_input<decl::Float>("Selection").default_value(1.0f).field_on_all();
41 break;
42 }
43 }
44}
45
46static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
47{
48 layout->prop(ptr, "domain", UI_ITEM_NONE, "", ICON_NONE);
49 layout->prop(ptr, "selection_type", UI_ITEM_NONE, "", ICON_NONE);
50}
51
52static void node_init(bNodeTree * /*tree*/, bNode *node)
53{
54 node->custom1 = int16_t(AttrDomain::Point);
55 node->custom2 = int16_t(SelectionType::Boolean);
56}
57
58static GField clamp_selection(const GField &selection)
59{
60 if (selection.cpp_type().is<bool>()) {
61 return selection;
62 }
63 static auto clamp = mf::build::SI1_SO<float, float>(
64 "Clamp", [](const float value) { return std::clamp(value, 0.0f, 1.0f); });
65 return Field<float>(FieldOperation::Create(clamp, {selection}));
66}
67
68static GField invert_selection(const GField &selection)
69{
70 if (selection.cpp_type().is<bool>()) {
71 static auto invert = mf::build::SI1_SO<bool, bool>("Invert Selection",
72 [](const bool value) { return !value; });
73 return GField(FieldOperation::Create(invert, {selection}));
74 }
75
76 static auto invert = mf::build::SI1_SO<float, float>(
77 "Invert Selection", [](const float value) { return 1.0f - value; });
78 return GField(FieldOperation::Create(invert, {selection}));
79}
80
87 const StringRef name,
88 const bke::AttrDomain domain)
89{
90 if (const std::optional<bke::AttributeMetaData> meta_data = attributes.lookup_meta_data(name)) {
91 if (meta_data->domain != domain) {
92 attributes.remove(name);
93 }
94 }
95}
96
98{
100 return;
101 }
102 GeometrySet geometry = params.extract_input<GeometrySet>("Geometry");
103 const eObjectMode mode = params.user_data()->call_data->operator_data->mode;
105 params.error_message_add(NodeWarningType::Error,
106 "Selection control is not supported in this mode");
107 params.set_output("Geometry", std::move(geometry));
108 return;
109 }
110
111 const GField selection = params.extract_input<GField>("Selection");
112 const AttrDomain domain = AttrDomain(params.node().custom1);
114 geometry.modify_geometry_sets([&](GeometrySet &geometry) {
115 if (Mesh *mesh = geometry.get_mesh_for_write()) {
116 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
117 remove_with_wrong_domain(attributes, ".select_vert", AttrDomain::Point);
118 remove_with_wrong_domain(attributes, ".select_edge", AttrDomain::Edge);
119 remove_with_wrong_domain(attributes, ".select_poly", AttrDomain::Face);
120 switch (mode) {
121 case OB_MODE_EDIT: {
122 const Field<bool> field = conversions.try_convert(selection, CPPType::get<bool>());
123 switch (domain) {
124 case AttrDomain::Point:
126 ".select_vert",
127 AttrDomain::Point,
128 field);
130 break;
131 case AttrDomain::Edge:
133 ".select_edge",
134 AttrDomain::Edge,
135 field);
137 break;
138 case AttrDomain::Face:
140 ".select_poly",
141 AttrDomain::Face,
142 field);
144 break;
145 default: {
146 break;
147 }
148 }
149 break;
150 }
151 case OB_MODE_SCULPT: {
152 GField on_domain = GField(
153 std::make_shared<bke::EvaluateOnDomainInput>(selection, domain));
154 GField clamped_and_inverted = invert_selection(clamp_selection(std::move(on_domain)));
155 const Field<float> field = conversions.try_convert(std::move(clamped_and_inverted),
158 ".sculpt_mask",
159 AttrDomain::Point,
160 field);
161 break;
162 }
163 default: {
164 break;
165 }
166 }
167 }
168 if (geometry.has_curves()) {
169 const GField field = clamp_selection(selection);
170 if (ELEM(domain, AttrDomain::Point, AttrDomain::Curve)) {
172 geometry.get_component_for_write<CurveComponent>(), ".selection", domain, field);
173 }
174 }
175 if (geometry.has_pointcloud()) {
176 const GField field = clamp_selection(selection);
177 if (domain == AttrDomain::Point) {
179 geometry.get_component_for_write<PointCloudComponent>(), ".selection", domain, field);
180 }
181 }
182 if (geometry.has_grease_pencil()) {
183 /* Grease Pencil only supports boolean selection. */
184 const Field<bool> field = conversions.try_convert(selection, CPPType::get<bool>());
185 if (ELEM(domain, AttrDomain::Point, AttrDomain::Curve)) {
187 geometry.get_component_for_write<GreasePencilComponent>(),
188 ".selection",
189 domain,
190 field);
191 }
192 }
193 });
194 params.set_output("Geometry", std::move(geometry));
195}
196
197static void node_rna(StructRNA *srna)
198{
200 "domain",
201 "Domain",
202 "",
205 int(AttrDomain::Point));
206 static EnumPropertyItem mode_items[] = {
208 "BOOLEAN",
209 0,
210 "Boolean",
211 "Store true or false selection values in edit mode"},
213 "FLOAT",
214 0,
215 "Float",
216 "Store floating point selection values. For mesh geometry, stored inverted as the sculpt "
217 "mode mask"},
218 {0, nullptr, 0, nullptr, nullptr},
219 };
221 "selection_type",
222 "Selection Type",
223 "",
224 mode_items,
227}
228
229static void node_register()
230{
231 static blender::bke::bNodeType ntype;
232 geo_node_type_base(&ntype, "GeometryNodeToolSetSelection", GEO_NODE_TOOL_SET_SELECTION);
233 ntype.ui_name = "Set Selection";
234 ntype.ui_description = "Set selection of the edited geometry, for tool execution";
235 ntype.enum_name_legacy = "TOOL_SELECTION_SET";
237 ntype.declare = node_declare;
238 ntype.initfunc = node_init;
243
244 node_rna(ntype.rna_ext.srna);
245}
247
248} // namespace blender::nodes::node_geo_tool_set_selection_cc
#define NODE_CLASS_GEOMETRY
Definition BKE_node.hh:447
#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 > Create(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:2748
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)
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 EnumPropertyItem rna_enum_attribute_domain_point_edge_face_curve_items[]
StructRNA * srna
Definition RNA_types.hh:909
int16_t custom1
int16_t custom2
Defines a node type.
Definition BKE_node.hh:226
std::string ui_description
Definition BKE_node.hh:232
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:277
NodeGeometryExecFunction geometry_node_execute
Definition BKE_node.hh:347
const char * enum_name_legacy
Definition BKE_node.hh:235
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:247
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
Definition BKE_node.hh:371
NodeDeclareFunction declare
Definition BKE_node.hh:355
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:4227