Blender V4.3
node_geo_grease_pencil_to_curves.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
5#include "BKE_curves.hh"
7#include "BKE_instances.hh"
8
10
11#include "node_geometry_util.hh"
12
14
16{
17 b.add_input<decl::Geometry>("Grease Pencil")
19 b.add_input<decl::Bool>("Selection")
20 .default_value(true)
21 .hide_value()
22 .field_on_all()
23 .description("Select the layers to convert");
24 b.add_input<decl::Bool>("Layers as Instances")
25 .default_value(true)
26 .description("Create a separate curve instance for every layer");
27 b.add_output<decl::Geometry>("Curves").propagate_all();
28}
29
31{
32 GeometrySet grease_pencil_geometry = params.extract_input<GeometrySet>("Grease Pencil");
33 const GreasePencil *grease_pencil = grease_pencil_geometry.get_grease_pencil();
34 if (!grease_pencil) {
35 params.set_default_remaining_outputs();
36 return;
37 }
38
39 const Span<const bke::greasepencil::Layer *> layers = grease_pencil->layers();
40 const int layers_num = layers.size();
41
42 const bke::GreasePencilFieldContext field_context{*grease_pencil};
43 const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
44 FieldEvaluator evaluator{field_context, layers_num};
45 evaluator.set_selection(selection_field);
46 evaluator.evaluate();
47 const IndexMask layer_selection = evaluator.get_evaluated_selection_as_mask();
48
49 const int instances_num = layer_selection.size();
50 if (instances_num == 0) {
51 params.set_default_remaining_outputs();
52 return;
53 }
54
55 bke::Instances *instances = new bke::Instances();
56 std::optional<int> empty_geometry_handle;
57
58 layer_selection.foreach_index([&](const int layer_i) {
59 const bke::greasepencil::Layer &layer = *layers[layer_i];
60 const bke::greasepencil::Drawing *drawing = grease_pencil->get_eval_drawing(layer);
61 const float4x4 transform = layer.local_transform();
62 if (!drawing) {
63 if (!empty_geometry_handle.has_value()) {
64 empty_geometry_handle = instances->add_reference(bke::InstanceReference());
65 }
66 instances->add_instance(*empty_geometry_handle, transform);
67 return;
68 }
69 const bke::CurvesGeometry &layer_strokes = drawing->strokes();
70 Curves *curves_id = bke::curves_new_nomain(layer_strokes);
71 curves_id->mat = static_cast<Material **>(MEM_dupallocN(grease_pencil->material_array));
72 curves_id->totcol = grease_pencil->material_array_num;
73 GeometrySet curves_geometry = GeometrySet::from_curves(curves_id);
74 curves_geometry.name = layer.name();
75 const int handle = instances->add_reference(std::move(curves_geometry));
76 instances->add_instance(handle, transform);
77 });
78
79 const bke::AttributeAccessor grease_pencil_attributes = grease_pencil->attributes();
80 bke::MutableAttributeAccessor instances_attributes = instances->attributes_for_write();
81 grease_pencil_attributes.foreach_attribute([&](const bke::AttributeIter &iter) {
82 if (ELEM(iter.name, "opacity")) {
83 return;
84 }
85 if (iter.data_type == CD_PROP_STRING) {
86 return;
87 }
88 const GAttributeReader src_attribute = iter.get();
89 if (!src_attribute) {
90 return;
91 }
92 if (src_attribute.varray.is_span() && src_attribute.sharing_info) {
93 /* Try reusing existing attribute array. */
94 instances_attributes.add(
95 iter.name,
96 AttrDomain::Instance,
97 iter.data_type,
98 bke::AttributeInitShared{src_attribute.varray.get_internal_span().data(),
99 *src_attribute.sharing_info});
100 return;
101 }
102 if (!instances_attributes.add(
103 iter.name, AttrDomain::Instance, iter.data_type, bke::AttributeInitConstruct()))
104 {
105 return;
106 }
107 bke::GSpanAttributeWriter dst_attribute = instances_attributes.lookup_for_write_span(
108 iter.name);
109 array_utils::gather(src_attribute.varray, layer_selection, dst_attribute.span);
110 dst_attribute.finish();
111 });
112
113 {
114 /* Manually propagate "opacity" data, because it's not a layer attribute on grease pencil
115 * yet. */
116 SpanAttributeWriter<float> opacity_attribute =
117 instances_attributes.lookup_or_add_for_write_only_span<float>("opacity",
118 AttrDomain::Instance);
119 layer_selection.foreach_index([&](const int layer_i, const int instance_i) {
120 opacity_attribute.span[instance_i] = grease_pencil->layer(layer_i).opacity;
121 });
122 opacity_attribute.finish();
123 }
124
125 GeometrySet curves_geometry = GeometrySet::from_instances(instances);
126 curves_geometry.name = std::move(grease_pencil_geometry.name);
127
128 const bool layers_as_instances = params.get_input<bool>("Layers as Instances");
129 if (!layers_as_instances) {
131 const NodeAttributeFilter attribute_filter = params.get_attribute_filter("Curves");
132 options.attribute_filter = attribute_filter;
133 curves_geometry = geometry::realize_instances(curves_geometry, options);
134 }
135
136 params.set_output("Curves", std::move(curves_geometry));
137}
138
139static void node_register()
140{
141 static bke::bNodeType ntype;
143 &ntype, GEO_NODE_GREASE_PENCIL_TO_CURVES, "Grease Pencil to Curves", NODE_CLASS_GEOMETRY);
145 ntype.declare = node_declare;
146 bke::node_type_size(&ntype, 160, 100, 320);
147
149}
151
152} // namespace blender::nodes::node_geo_grease_pencil_to_curves_cc
Low-level operations for curves.
Low-level operations for grease pencil.
#define NODE_CLASS_GEOMETRY
Definition BKE_node.hh:418
#define ELEM(...)
@ CD_PROP_STRING
#define NOD_REGISTER_NODE(REGISTER_FUNC)
constexpr int64_t size() const
Definition BLI_span.hh:253
void foreach_attribute(const FunctionRef< void(const AttributeIter &)> fn) const
GAttributeReader get() const
bool add(const StringRef attribute_id, const AttrDomain domain, const eCustomDataType data_type, const AttributeInit &initializer)
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type)
GSpanAttributeWriter lookup_for_write_span(StringRef attribute_id)
const bke::CurvesGeometry & strokes() const
void set_selection(Field< bool > selection)
Definition FN_field.hh:385
void foreach_index(Fn &&fn) const
local_group_size(16, 16) .push_constant(Type b
CCL_NAMESPACE_BEGIN struct Options options
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
void gather(const GVArray &src, const IndexMask &indices, GMutableSpan dst, int64_t grain_size=4096)
void node_type_size(bNodeType *ntype, int width, int minwidth, int maxwidth)
Definition node.cc:4602
void node_register_type(bNodeType *ntype)
Definition node.cc:1708
Curves * curves_new_nomain(int points_num, int curves_num)
bke::GeometrySet realize_instances(bke::GeometrySet geometry_set, const RealizeInstancesOptions &options)
void geo_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
struct Material ** mat
const ImplicitSharingInfo * sharing_info
static GeometrySet from_instances(Instances *instances, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
static GeometrySet from_curves(Curves *curves, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
const GreasePencil * get_grease_pencil() const
Defines a node type.
Definition BKE_node.hh:218
NodeGeometryExecFunction geometry_node_execute
Definition BKE_node.hh:339
NodeDeclareFunction declare
Definition BKE_node.hh:347