Blender V4.5
node_geo_merge_layers.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
6
7#include "GEO_merge_layers.hh"
8
10
11#include "NOD_rna_define.hh"
12
13#include "UI_interface.hh"
14#include "UI_resources.hh"
15
17
19
20enum class MergeLayerMode {
21 ByName = 0,
22 ByID = 1,
23};
24
26{
27 b.use_custom_socket_order();
28 b.allow_any_socket_order();
29 b.add_default_layout();
30 b.add_input<decl::Geometry>("Grease Pencil")
31 .supported_type(GeometryComponent::Type::GreasePencil);
32 b.add_output<decl::Geometry>("Grease Pencil").propagate_all().align_with_previous();
33 b.add_input<decl::Bool>("Selection").default_value(true).hide_value().field_on_all();
34 auto &group_id = b.add_input<decl::Int>("Group ID")
35 .hide_value()
36 .field_on_all()
37 .make_available([](bNode &node) {
38 node_storage(node).mode = int8_t(MergeLayerMode::ByID);
39 });
40
41 const bNode *node = b.node_or_null();
42 if (node) {
43 const NodeGeometryMergeLayers &storage = node_storage(*node);
44 const MergeLayerMode mode = MergeLayerMode(storage.mode);
45 group_id.available(mode == MergeLayerMode::ByID);
46 }
47}
48
49static void node_init(bNodeTree * /*tree*/, bNode *node)
50{
52 data->mode = int8_t(MergeLayerMode::ByName);
53 node->storage = data;
54}
55
56static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
57{
58 layout->prop(ptr, "mode", UI_ITEM_NONE, "", ICON_NONE);
59}
60
63{
64 using namespace bke::greasepencil;
65
66 const int old_layers_num = src_grease_pencil.layers().size();
67
68 const Field<bool> selection_field = params.get_input<Field<bool>>("Selection");
69
70 bke::GreasePencilFieldContext field_context{src_grease_pencil};
71 FieldEvaluator field_evaluator{field_context, old_layers_num};
72 field_evaluator.add(selection_field);
73 field_evaluator.evaluate();
74 const VArray<bool> selection = field_evaluator.get_evaluated<bool>(0);
75
76 Vector<Vector<int>> layers_map;
77 Map<StringRef, int> new_layer_index_by_name;
78
79 for (const int layer_i : IndexRange(old_layers_num)) {
80 const bool is_selected = selection[layer_i];
81 if (!is_selected) {
82 layers_map.append({layer_i});
83 continue;
84 }
85
86 const Layer &layer = src_grease_pencil.layer(layer_i);
87 const int new_layer_index = new_layer_index_by_name.lookup_or_add_cb(
88 layer.name(), [&]() { return layers_map.append_and_get_index_as(); });
89 layers_map[new_layer_index].append(layer_i);
90 }
91 return layers_map;
92}
93
94static Vector<Vector<int>> get_layers_map_by_id(const GreasePencil &src_grease_pencil,
96{
97 using namespace bke::greasepencil;
98
99 const int old_layers_num = src_grease_pencil.layers().size();
100
101 const Field<bool> selection_field = params.get_input<Field<bool>>("Selection");
102 const Field<int> group_id_field = params.get_input<Field<int>>("Group ID");
103
104 bke::GreasePencilFieldContext field_context{src_grease_pencil};
105 FieldEvaluator field_evaluator{field_context, old_layers_num};
106 field_evaluator.add(selection_field);
107 field_evaluator.add(group_id_field);
108 field_evaluator.evaluate();
109 const VArray<bool> selection = field_evaluator.get_evaluated<bool>(0);
110 const VArray<int> group_ids = field_evaluator.get_evaluated<int>(1);
111
112 Vector<Vector<int>> layers_map;
113 Map<int, int> new_layer_index_by_id;
114
115 for (const int layer_i : IndexRange(old_layers_num)) {
116 const bool is_selected = selection[layer_i];
117 if (!is_selected) {
118 layers_map.append({layer_i});
119 continue;
120 }
121 const int group_id = group_ids[layer_i];
122 const int new_layer_index = new_layer_index_by_id.lookup_or_add_cb(
123 group_id, [&]() { return layers_map.append_and_get_index_as(); });
124 layers_map[new_layer_index].append(layer_i);
125 }
126 return layers_map;
127}
128
130 const NodeGeometryMergeLayers &storage,
132 const AttributeFilter &attribute_filter)
133{
134 using namespace bke::greasepencil;
135
136 const GreasePencil *src_grease_pencil = geometry.get_grease_pencil();
137 if (!src_grease_pencil) {
138 return;
139 }
140 const int old_layers_num = src_grease_pencil->layers().size();
141
142 Vector<Vector<int>> layers_map;
143 switch (MergeLayerMode(storage.mode)) {
145 layers_map = get_layers_map_by_name(*src_grease_pencil, params);
146 break;
147 }
149 layers_map = get_layers_map_by_id(*src_grease_pencil, params);
150 break;
151 }
152 }
153
154 const int new_layers_num = layers_map.size();
155 if (old_layers_num == new_layers_num) {
156 return;
157 }
158
159 GreasePencil *new_grease_pencil = geometry::merge_layers(
160 *src_grease_pencil, layers_map, attribute_filter);
161 geometry.replace_grease_pencil(new_grease_pencil);
162}
163
165{
166 GeometrySet main_geometry = params.extract_input<GeometrySet>("Grease Pencil");
167 const bNode &node = params.node();
168 const NodeGeometryMergeLayers &storage = node_storage(node);
169
170 const NodeAttributeFilter attribute_filter = params.get_attribute_filter("Grease Pencil");
171
172 main_geometry.modify_geometry_sets(
173 [&](GeometrySet &geometry) { merge_layers(geometry, storage, params, attribute_filter); });
174
175 params.set_output("Grease Pencil", std::move(main_geometry));
176}
177
178static void node_rna(StructRNA *srna)
179{
180 static const EnumPropertyItem mode_items[] = {
182 "MERGE_BY_NAME",
183 0,
184 "By Name",
185 "Combine all layers which have the same name"},
187 "MERGE_BY_ID",
188 0,
189 "By Group ID",
190 "Provide a custom group ID for each layer and all layers with the same ID will be merged "
191 "into one"},
192 {0, nullptr, 0, nullptr, nullptr},
193 };
194
196 "mode",
197 "Mode",
198 "Determines how to choose which layers are merged",
199 mode_items,
202 nullptr);
203}
204
205static void node_register()
206{
207 static blender::bke::bNodeType ntype;
208
209 geo_node_type_base(&ntype, "GeometryNodeMergeLayers", GEO_NODE_MERGE_LAYERS);
210 ntype.ui_name = "Merge Layers";
211 ntype.ui_description = "Join groups of Grease Pencil layers into one";
212 ntype.enum_name_legacy = "MERGE_LAYERS";
214 ntype.declare = node_declare;
215 ntype.initfunc = node_init;
219 ntype, "NodeGeometryMergeLayers", node_free_standard_storage, node_copy_standard_storage);
221
222 node_rna(ntype.rna_ext.srna);
223}
225
226} // namespace blender::nodes::node_geo_merge_layers_cc
Low-level operations for grease pencil.
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1215
#define NODE_CLASS_GEOMETRY
Definition BKE_node.hh:447
#define GEO_NODE_MERGE_LAYERS
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define NOD_storage_enum_accessors(member)
#define UI_ITEM_NONE
BMesh const char void * data
Value & lookup_or_add_cb(const Key &key, const CreateValueF &create_value)
Definition BLI_map.hh:620
int64_t size() const
int add(GField field, GVArray *varray_ptr)
Definition field.cc:751
const GVArray & get_evaluated(const int field_index) const
Definition FN_field.hh:448
void make_available(bNode &node) const
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void node_register_type(bNodeType &ntype)
Definition node.cc:2748
void node_type_storage(bNodeType &ntype, std::optional< StringRefNull > storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
Definition node.cc:5603
GreasePencil * merge_layers(const GreasePencil &src_grease_pencil, Span< Vector< int > > layers_to_merge, const bke::AttributeFilter &attribute_filter)
static Vector< Vector< int > > get_layers_map_by_name(const GreasePencil &src_grease_pencil, const GeoNodeExecParams &params)
static void merge_layers(GeometrySet &geometry, const NodeGeometryMergeLayers &storage, const GeoNodeExecParams &params, const AttributeFilter &attribute_filter)
static void node_init(bNodeTree *, bNode *node)
static void node_geo_exec(GeoNodeExecParams params)
static void node_declare(NodeDeclarationBuilder &b)
static Vector< Vector< int > > get_layers_map_by_id(const GreasePencil &src_grease_pencil, const GeoNodeExecParams &params)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
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)
void geo_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
void node_free_standard_storage(bNode *node)
Definition node_util.cc:42
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
Definition node_util.cc:54
StructRNA * srna
Definition RNA_types.hh:909
void * storage
void modify_geometry_sets(ForeachSubGeometryCallback callback)
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
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:4226