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