Blender V5.0
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
7#include "BLI_math_matrix.hh"
8
10#include "BKE_curves.hh"
11#include "BKE_grease_pencil.hh"
12
14
15namespace blender::geometry {
16
17static bke::CurvesGeometry join_curves(const GreasePencil &src_grease_pencil,
18 const Span<const bke::CurvesGeometry *> all_src_curves,
19 const Span<float4x4> transforms_to_apply,
20 const bke::AttributeFilter &attribute_filter)
21{
22 BLI_assert(all_src_curves.size() == transforms_to_apply.size());
23 Vector<bke::GeometrySet> src_geometries(all_src_curves.size());
24 for (const int src_curves_i : all_src_curves.index_range()) {
25 bke::CurvesGeometry src_curves = *all_src_curves[src_curves_i];
26 if (src_curves.is_empty()) {
27 continue;
28 }
29 const float4x4 &transform = transforms_to_apply[src_curves_i];
30 src_curves.transform(transform);
31 Curves *src_curves_id = bke::curves_new_nomain(std::move(src_curves));
32 src_curves_id->mat = static_cast<Material **>(MEM_dupallocN(src_grease_pencil.material_array));
33 src_curves_id->totcol = src_grease_pencil.material_array_num;
34 src_geometries[src_curves_i].replace_curves(src_curves_id);
35 }
36 bke::GeometrySet joined_geometry = join_geometries(src_geometries, attribute_filter);
37 if (joined_geometry.has_curves()) {
38 return joined_geometry.get_curves()->geometry.wrap();
39 }
40 return {};
41}
42
43GreasePencil *merge_layers(const GreasePencil &src_grease_pencil,
44 const Span<Vector<int>> layers_to_merge,
45 const bke::AttributeFilter &attribute_filter)
46{
47 using namespace bke::greasepencil;
48
49 GreasePencil *new_grease_pencil = BKE_grease_pencil_new_nomain();
50
51 BKE_grease_pencil_copy_parameters(src_grease_pencil, *new_grease_pencil);
52 new_grease_pencil->runtime->eval_frame = src_grease_pencil.runtime->eval_frame;
53
54 const int new_layers_num = layers_to_merge.size();
55 new_grease_pencil->add_layers_with_empty_drawings_for_eval(new_layers_num);
56 Vector<bke::CurvesGeometry *> curves_by_new_layer(new_layers_num);
57
58 for (const int new_layer_i : IndexRange(new_layers_num)) {
59 Layer &layer = new_grease_pencil->layer(new_layer_i);
60 const Span<int> src_layer_indices = layers_to_merge[new_layer_i];
61 BLI_assert(!src_layer_indices.is_empty());
62 const int first_src_layer_i = src_layer_indices[0];
63 const Layer &first_src_layer = src_grease_pencil.layer(first_src_layer_i);
64 layer.set_name(first_src_layer.name());
65 layer.opacity = first_src_layer.opacity;
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 == bke::AttrType::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.
void BKE_grease_pencil_copy_parameters(const GreasePencil &src, GreasePencil &dst)
GreasePencil * BKE_grease_pencil_new_nomain()
#define BLI_assert(a)
Definition BLI_assert.h:46
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
const CPPType & type() const
MutableSpan< T > typed() const
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr bool is_empty() const
Definition BLI_span.hh:260
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, AttrType data_type)
bke::CurvesGeometry & strokes_for_write()
void set_local_transform(const float4x4 &transform)
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
#define T
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)
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, bool allow_merging_instance_references=true)
GreasePencil * merge_layers(const GreasePencil &src_grease_pencil, Span< Vector< int > > layers_to_merge, const bke::AttributeFilter &attribute_filter)
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:93
MatBase< float, 4, 4 > float4x4
CurvesGeometry geometry
struct Material ** mat
struct Material ** material_array
GreasePencilRuntimeHandle * runtime
bool allow_skip(const StringRef name) const
const Curves * get_curves() const
i
Definition text_draw.cc:230