Blender V4.3
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
5#include "GEO_merge_layers.hh"
6
8#include "BKE_curves.hh"
10#include "BKE_lib_id.hh"
11
13
14namespace blender::geometry {
15
16static bke::CurvesGeometry join_curves(const GreasePencil &src_grease_pencil,
17 const Span<const bke::CurvesGeometry *> all_src_curves,
18 const Span<float4x4> transforms_to_apply,
19 const bke::AttributeFilter &attribute_filter)
20{
21 BLI_assert(all_src_curves.size() == transforms_to_apply.size());
22 Vector<bke::GeometrySet> src_geometries(all_src_curves.size());
23 for (const int src_curves_i : all_src_curves.index_range()) {
24 bke::CurvesGeometry src_curves = *all_src_curves[src_curves_i];
25 if (src_curves.curves_num() == 0) {
26 continue;
27 }
28 const float4x4 &transform = transforms_to_apply[src_curves_i];
29 src_curves.transform(transform);
30 Curves *src_curves_id = bke::curves_new_nomain(std::move(src_curves));
31 src_curves_id->mat = static_cast<Material **>(MEM_dupallocN(src_grease_pencil.material_array));
32 src_curves_id->totcol = src_grease_pencil.material_array_num;
33 src_geometries[src_curves_i].replace_curves(src_curves_id);
34 }
35 bke::GeometrySet joined_geometry = join_geometries(src_geometries, attribute_filter);
36 if (joined_geometry.has_curves()) {
37 return joined_geometry.get_curves()->geometry.wrap();
38 }
39 return {};
40}
41
42GreasePencil *merge_layers(const GreasePencil &src_grease_pencil,
43 const Span<Vector<int>> layers_to_merge,
44 const bke::AttributeFilter &attribute_filter)
45{
46 using namespace bke::greasepencil;
47
48 GreasePencil *new_grease_pencil = BKE_grease_pencil_new_nomain();
49
50 new_grease_pencil->runtime->eval_frame = src_grease_pencil.runtime->eval_frame;
51 new_grease_pencil->material_array = static_cast<Material **>(
52 MEM_dupallocN(src_grease_pencil.material_array));
53 new_grease_pencil->material_array_num = src_grease_pencil.material_array_num;
54
55 const int new_layers_num = layers_to_merge.size();
56 new_grease_pencil->add_layers_with_empty_drawings_for_eval(new_layers_num);
57 Vector<bke::CurvesGeometry *> curves_by_new_layer(new_layers_num);
58
59 for (const int new_layer_i : IndexRange(new_layers_num)) {
60 Layer &layer = new_grease_pencil->layer(new_layer_i);
61 const Span<int> src_layer_indices = layers_to_merge[new_layer_i];
62 BLI_assert(!src_layer_indices.is_empty());
63 const int first_src_layer_i = src_layer_indices[0];
64 const Layer &first_src_layer = src_grease_pencil.layer(first_src_layer_i);
65 layer.set_name(first_src_layer.name());
66 Drawing *drawing = new_grease_pencil->get_eval_drawing(layer);
67 BLI_assert(drawing != nullptr);
68 curves_by_new_layer[new_layer_i] = &drawing->strokes_for_write();
69 }
70
71 threading::parallel_for(IndexRange(new_layers_num), 32, [&](const IndexRange new_layers_range) {
72 for (const int new_layer_i : new_layers_range) {
73 Layer &new_layer = new_grease_pencil->layer(new_layer_i);
74
75 const Span<int> src_layer_indices = layers_to_merge[new_layer_i];
76 const int first_src_layer_i = src_layer_indices[0];
77 const Layer &first_src_layer = src_grease_pencil.layer(first_src_layer_i);
78
79 const float4x4 new_layer_transform = first_src_layer.local_transform();
80 new_layer.set_local_transform(new_layer_transform);
81
82 bke::CurvesGeometry &new_curves = *curves_by_new_layer[new_layer_i];
83
84 if (src_layer_indices.size() == 1) {
85 /* Optimization for the case if the new layer corresponds to exactly one source layer. */
86 if (const Drawing *src_drawing = src_grease_pencil.get_eval_drawing(first_src_layer)) {
87 const bke::CurvesGeometry &src_curves = src_drawing->strokes();
88 new_curves = src_curves;
89 }
90 continue;
91 }
92
93 /* Needed to transform the positions from all spaces into the same space. */
94 const float4x4 new_layer_transform_inv = math::invert(new_layer_transform);
95
97 Vector<float4x4> transforms_to_apply;
98 for (const int i : src_layer_indices.index_range()) {
99 const int src_layer_i = src_layer_indices[i];
100 const Layer &src_layer = src_grease_pencil.layer(src_layer_i);
101 if (const Drawing *src_drawing = src_grease_pencil.get_eval_drawing(src_layer)) {
102 const bke::CurvesGeometry &src_curves = src_drawing->strokes();
103 all_src_curves.append(&src_curves);
104 transforms_to_apply.append(new_layer_transform_inv * src_layer.local_transform());
105 }
106 }
107 new_curves = join_curves(
108 src_grease_pencil, all_src_curves, transforms_to_apply, attribute_filter);
109 }
110 });
111
112 const bke::AttributeAccessor src_attributes = src_grease_pencil.attributes();
113 bke::MutableAttributeAccessor new_attributes = new_grease_pencil->attributes_for_write();
114 src_attributes.foreach_attribute([&](const bke::AttributeIter &iter) {
115 if (iter.data_type == CD_PROP_STRING) {
116 return;
117 }
118 if (attribute_filter.allow_skip(iter.name)) {
119 return;
120 }
121 bke::GAttributeReader src_attribute = iter.get();
124
125 const CPPType &type = new_attribute.span.type();
126
128 using T = decltype(type);
129 const VArraySpan<T> src_span = src_attribute.varray.typed<T>();
130 MutableSpan<T> new_span = new_attribute.span.typed<T>();
131
133 for (const int new_layer_i : IndexRange(new_layers_num)) {
134 const Span<int> src_layer_indices = layers_to_merge[new_layer_i];
135 for (const int src_layer_i : src_layer_indices) {
136 const T &src_value = src_span[src_layer_i];
137 mixer.mix_in(new_layer_i, src_value);
138 }
139 }
140
141 mixer.finalize();
142 });
143
144 new_attribute.finish();
145 });
146
147 return new_grease_pencil;
148}
149
150} // namespace blender::geometry
Low-level operations for curves.
Low-level operations for grease pencil.
GreasePencil * BKE_grease_pencil_new_nomain()
#define BLI_assert(a)
Definition BLI_assert.h:50
@ CD_PROP_STRING
const CPPType & type() const
MutableSpan< T > typed() const
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
constexpr bool is_empty() const
Definition BLI_span.hh:261
void append(const T &value)
GAttributeReader get() const
void transform(const float4x4 &matrix)
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type)
bke::CurvesGeometry & strokes_for_write()
void set_local_transform(const float4x4 &transform)
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
typename DefaultMixerStruct< T >::type DefaultMixer
Curves * curves_new_nomain(int points_num, int curves_num)
GreasePencil * merge_layers(const GreasePencil &src_grease_pencil, Span< Vector< int > > layers_to_merge, const bke::AttributeFilter &attribute_filter)
bke::GeometrySet join_geometries(Span< bke::GeometrySet > geometries, const bke::AttributeFilter &attribute_filter, const std::optional< Span< bke::GeometryComponent::Type > > &component_types_to_join=std::nullopt)
static bke::CurvesGeometry join_curves(const GreasePencil &src_grease_pencil, const Span< const bke::CurvesGeometry * > all_src_curves, const Span< float4x4 > transforms_to_apply, const bke::AttributeFilter &attribute_filter)
CartesianBasis invert(const CartesianBasis &basis)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:95
CurvesGeometry geometry
struct Material ** mat
struct Material ** material_array
GreasePencilRuntimeHandle * runtime
bool allow_skip(const StringRef name) const
const Curves * get_curves() const