Blender V4.3
grease_pencil.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <iostream>
10#include <optional>
11
12#include "BKE_action.hh"
13#include "BKE_anim_data.hh"
14#include "BKE_animsys.h"
16#include "BKE_curves.hh"
17#include "BKE_customdata.hh"
18#include "BKE_deform.hh"
19#include "BKE_geometry_set.hh"
20#include "BKE_grease_pencil.h"
21#include "BKE_grease_pencil.hh"
22#include "BKE_idtype.hh"
23#include "BKE_lib_id.hh"
24#include "BKE_lib_query.hh"
25#include "BKE_main.hh"
26#include "BKE_material.h"
27#include "BKE_modifier.hh"
28#include "BKE_object.hh"
29#include "BKE_object_types.hh"
30
31#include "BLI_bounds.hh"
33#include "BLI_map.hh"
35#include "BLI_math_geom.h"
36#include "BLI_math_matrix.h"
37#include "BLI_math_matrix.hh"
40#include "BLI_memarena.h"
41#include "BLI_memory_utils.hh"
42#include "BLI_polyfill_2d.h"
43#include "BLI_span.hh"
44#include "BLI_stack.hh"
45#include "BLI_string.h"
46#include "BLI_string_ref.hh"
47#include "BLI_string_utils.hh"
48#include "BLI_utildefines.h"
49#include "BLI_vector_set.hh"
50#include "BLI_virtual_array.hh"
51
52#include "BLO_read_write.hh"
53
54#include "BLT_translation.hh"
55
56#include "DNA_ID.h"
57#include "DNA_ID_enums.h"
58#include "DNA_brush_types.h"
59#include "DNA_defaults.h"
62#include "DNA_material_types.h"
63#include "DNA_modifier_types.h"
64
65#include "DEG_depsgraph.hh"
67
68#include "MEM_guardedalloc.h"
69
70using blender::float3;
71using blender::Span;
72using blender::uint3;
74
75static const char *ATTR_POSITION = "position";
76
77/* Forward declarations. */
78static void read_drawing_array(GreasePencil &grease_pencil, BlendDataReader *reader);
79static void write_drawing_array(GreasePencil &grease_pencil, BlendWriter *writer);
80static void free_drawing_array(GreasePencil &grease_pencil);
81
82static void read_layer_tree(GreasePencil &grease_pencil, BlendDataReader *reader);
83static void write_layer_tree(GreasePencil &grease_pencil, BlendWriter *writer);
84
86{
87 using namespace blender::bke;
88
89 GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(id);
90 BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(grease_pencil, id));
91
93
94 grease_pencil->root_group_ptr = MEM_new<greasepencil::LayerGroup>(__func__);
95 grease_pencil->set_active_node(nullptr);
96
97 CustomData_reset(&grease_pencil->layers_data);
98
99 grease_pencil->runtime = MEM_new<GreasePencilRuntime>(__func__);
100}
101
102static void grease_pencil_copy_data(Main * /*bmain*/,
103 std::optional<Library *> /*owner_library*/,
104 ID *id_dst,
105 const ID *id_src,
106 const int /*flag*/)
107{
108 using namespace blender;
109
110 GreasePencil *grease_pencil_dst = reinterpret_cast<GreasePencil *>(id_dst);
111 const GreasePencil *grease_pencil_src = reinterpret_cast<const GreasePencil *>(id_src);
112
113 /* Duplicate material array. */
114 grease_pencil_dst->material_array = static_cast<Material **>(
115 MEM_dupallocN(grease_pencil_src->material_array));
116
117 BKE_grease_pencil_duplicate_drawing_array(grease_pencil_src, grease_pencil_dst);
118
119 /* Duplicate layer tree. */
120 grease_pencil_dst->root_group_ptr = MEM_new<bke::greasepencil::LayerGroup>(
121 __func__, grease_pencil_src->root_group());
122
123 /* Set active node. */
124 if (grease_pencil_src->get_active_node()) {
125 bke::greasepencil::TreeNode *active_node = grease_pencil_dst->find_node_by_name(
126 grease_pencil_src->get_active_node()->name());
127 BLI_assert(active_node);
128 grease_pencil_dst->set_active_node(active_node);
129 }
130
131 CustomData_init_from(&grease_pencil_src->layers_data,
132 &grease_pencil_dst->layers_data,
134 grease_pencil_dst->layers().size());
135
136 BKE_defgroup_copy_list(&grease_pencil_dst->vertex_group_names,
137 &grease_pencil_src->vertex_group_names);
138
139 /* Make sure the runtime pointer exists. */
140 grease_pencil_dst->runtime = MEM_new<bke::GreasePencilRuntime>(__func__);
141
142 if (grease_pencil_src->runtime->bake_materials) {
143 grease_pencil_dst->runtime->bake_materials = std::make_unique<bke::bake::BakeMaterialsList>(
144 *grease_pencil_src->runtime->bake_materials);
145 }
146}
147
149{
150 GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(id);
151 BKE_animdata_free(&grease_pencil->id, false);
152
153 MEM_SAFE_FREE(grease_pencil->material_array);
154
155 CustomData_free(&grease_pencil->layers_data, grease_pencil->layers().size());
156
157 free_drawing_array(*grease_pencil);
158 MEM_delete(&grease_pencil->root_group());
159
160 BLI_freelistN(&grease_pencil->vertex_group_names);
161
163
164 MEM_delete(grease_pencil->runtime);
165 grease_pencil->runtime = nullptr;
166}
167
169{
170 GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(id);
171 for (int i = 0; i < grease_pencil->material_array_num; i++) {
173 }
174 for (GreasePencilDrawingBase *drawing_base : grease_pencil->drawings()) {
175 if (drawing_base->type == GP_DRAWING_REFERENCE) {
176 GreasePencilDrawingReference *drawing_reference =
177 reinterpret_cast<GreasePencilDrawingReference *>(drawing_base);
179 }
180 }
181 for (const blender::bke::greasepencil::Layer *layer : grease_pencil->layers()) {
182 if (layer->parent) {
184 }
185 }
186}
187
188static void grease_pencil_blend_write(BlendWriter *writer, ID *id, const void *id_address)
189{
190 GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(id);
191
192 blender::Vector<CustomDataLayer, 16> layers_data_layers;
193 CustomData_blend_write_prepare(grease_pencil->layers_data, layers_data_layers);
194
195 /* Write LibData */
196 BLO_write_id_struct(writer, GreasePencil, id_address, &grease_pencil->id);
197 BKE_id_blend_write(writer, &grease_pencil->id);
198
200 &grease_pencil->layers_data,
201 layers_data_layers,
202 grease_pencil->layers().size(),
204 id);
205
206 /* Write drawings. */
207 write_drawing_array(*grease_pencil, writer);
208 /* Write layer tree. */
209 write_layer_tree(*grease_pencil, writer);
210
211 /* Write materials. */
213 writer, grease_pencil->material_array_num, grease_pencil->material_array);
214 /* Write vertex group names. */
215 BKE_defbase_blend_write(writer, &grease_pencil->vertex_group_names);
216}
217
219{
220 using namespace blender::bke::greasepencil;
221 GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(id);
222
223 /* Read drawings. */
224 read_drawing_array(*grease_pencil, reader);
225 /* Read layer tree. */
226 read_layer_tree(*grease_pencil, reader);
227
228 CustomData_blend_read(reader, &grease_pencil->layers_data, grease_pencil->layers().size());
229
230 /* Read materials. */
232 grease_pencil->material_array_num,
233 reinterpret_cast<void **>(&grease_pencil->material_array));
234 /* Read vertex group names. */
235 BLO_read_struct_list(reader, bDeformGroup, &grease_pencil->vertex_group_names);
236
237 grease_pencil->runtime = MEM_new<blender::bke::GreasePencilRuntime>(__func__);
238}
239
241 /*id_code*/ ID_GP,
242 /*id_filter*/ FILTER_ID_GP,
243 /*dependencies_id_types*/ FILTER_ID_GP | FILTER_ID_MA,
244 /*main_listbase_index*/ INDEX_ID_GP,
245 /*struct_size*/ sizeof(GreasePencil),
246 /*name*/ "GreasePencil",
247 /*name_plural*/ N_("grease_pencils_v3"),
248 /*translation_context*/ BLT_I18NCONTEXT_ID_GPENCIL,
250 /*asset_type_info*/ nullptr,
251
252 /*init_data*/ grease_pencil_init_data,
253 /*copy_data*/ grease_pencil_copy_data,
254 /*free_data*/ grease_pencil_free_data,
255 /*make_local*/ nullptr,
256 /*foreach_id*/ grease_pencil_foreach_id,
257 /*foreach_cache*/ nullptr,
258 /*foreach_path*/ nullptr,
259 /*owner_pointer_get*/ nullptr,
260
261 /*blend_write*/ grease_pencil_blend_write,
262 /*blend_read_data*/ grease_pencil_blend_read_data,
263 /*blend_read_after_liblink*/ nullptr,
264
265 /*blend_read_undo_preserve*/ nullptr,
266
267 /*lib_override_apply_post*/ nullptr,
268};
269
271
272static const std::string ATTR_RADIUS = "radius";
273static const std::string ATTR_OPACITY = "opacity";
274static const std::string ATTR_VERTEX_COLOR = "vertex_color";
275static const std::string ATTR_FILL_COLOR = "fill_color";
276
277/* Curves attributes getters */
278static int domain_num(const CurvesGeometry &curves, const AttrDomain domain)
279{
280 return domain == AttrDomain::Point ? curves.points_num() : curves.curves_num();
281}
283{
284 return domain == AttrDomain::Point ? curves.point_data : curves.curve_data;
285}
286template<typename T>
288 const AttrDomain domain,
289 const StringRef name,
290 const T default_value = T())
291{
292 const int num = domain_num(curves, domain);
293 if (num <= 0) {
294 return {};
295 }
297 CustomData &custom_data = domain_custom_data(curves, domain);
298
299 T *data = (T *)CustomData_get_layer_named_for_write(&custom_data, type, name, num);
300 if (data != nullptr) {
301 return {data, num};
302 }
303 data = (T *)CustomData_add_layer_named(&custom_data, type, CD_SET_DEFAULT, num, name);
304 MutableSpan<T> span = {data, num};
305 if (span.first() != default_value) {
306 span.fill(default_value);
307 }
308 return span;
309}
310
312{
313 this->base.type = GP_DRAWING;
314 this->base.flag = 0;
315
316 new (&this->geometry) bke::CurvesGeometry();
317 /* Initialize runtime data. */
318 this->runtime = MEM_new<bke::greasepencil::DrawingRuntime>(__func__);
319}
320
322{
323 this->base.type = GP_DRAWING;
324 this->base.flag = other.base.flag;
325
326 new (&this->geometry) bke::CurvesGeometry(other.strokes());
327 /* Initialize runtime data. */
328 this->runtime = MEM_new<bke::greasepencil::DrawingRuntime>(__func__);
329
330 this->runtime->triangle_offsets_cache = other.runtime->triangle_offsets_cache;
331 this->runtime->triangles_cache = other.runtime->triangles_cache;
332 this->runtime->curve_plane_normals_cache = other.runtime->curve_plane_normals_cache;
333 this->runtime->curve_texture_matrices = other.runtime->curve_texture_matrices;
334}
335
337{
338 this->base.type = GP_DRAWING;
339 other.base.type = GP_DRAWING;
340 this->base.flag = other.base.flag;
341 other.base.flag = 0;
342
343 new (&this->geometry) bke::CurvesGeometry(std::move(other.geometry.wrap()));
344
345 this->runtime = other.runtime;
346 other.runtime = nullptr;
347}
348
350{
351 if (this == &other) {
352 return *this;
353 }
354 std::destroy_at(this);
355 new (this) Drawing(other);
356 return *this;
357}
358
360{
361 if (this == &other) {
362 return *this;
363 }
364 std::destroy_at(this);
365 new (this) Drawing(std::move(other));
366 return *this;
367}
368
370{
371 this->strokes().~CurvesGeometry();
372 MEM_delete(this->runtime);
373 this->runtime = nullptr;
374}
375
376OffsetIndices<int> Drawing::triangle_offsets() const
377{
378 this->runtime->triangle_offsets_cache.ensure([&](Vector<int> &r_offsets) {
379 const CurvesGeometry &curves = this->strokes();
380 const OffsetIndices<int> points_by_curve = curves.evaluated_points_by_curve();
381
382 int offset = 0;
383 r_offsets.reinitialize(curves.curves_num() + 1);
384 for (const int curve_i : points_by_curve.index_range()) {
385 const IndexRange points = points_by_curve[curve_i];
386 r_offsets[curve_i] = offset;
387 offset += std::max(int(points.size() - 2), 0);
388 }
389 r_offsets.last() = offset;
390 });
391 return this->runtime->triangle_offsets_cache.data().as_span();
392}
393
394static void update_triangle_cache(const Span<float3> positions,
395 const Span<float3> normals,
396 const OffsetIndices<int> points_by_curve,
397 const OffsetIndices<int> triangle_offsets,
398 const IndexMask &curve_mask,
399 MutableSpan<uint3> triangles)
400{
401 struct LocalMemArena {
402 MemArena *pf_arena = nullptr;
403 LocalMemArena() : pf_arena(BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "Drawing::triangles")) {}
404
405 ~LocalMemArena()
406 {
407 if (pf_arena != nullptr) {
408 BLI_memarena_free(pf_arena);
409 }
410 }
411 };
413 curve_mask.foreach_segment(GrainSize(32), [&](const IndexMaskSegment mask_segment) {
414 MemArena *pf_arena = all_local_mem_arenas.local().pf_arena;
415 for (const int curve_i : mask_segment) {
416 const IndexRange points = points_by_curve[curve_i];
417 if (points.size() < 3) {
418 continue;
419 }
420 MutableSpan<uint3> r_tris = triangles.slice(triangle_offsets[curve_i]);
421
422 float(*projverts)[2] = static_cast<float(*)[2]>(
423 BLI_memarena_alloc(pf_arena, sizeof(*projverts) * size_t(points.size())));
424
425 float3x3 axis_mat;
426 axis_dominant_v3_to_m3(axis_mat.ptr(), normals[curve_i]);
427
428 for (const int i : IndexRange(points.size())) {
429 mul_v2_m3v3(projverts[i], axis_mat.ptr(), positions[points[i]]);
430 }
431
433 projverts, points.size(), 0, reinterpret_cast<uint32_t(*)[3]>(r_tris.data()), pf_arena);
434 BLI_memarena_clear(pf_arena);
435 }
436 });
437}
438
440{
441 const CurvesGeometry &curves = this->strokes();
442 const OffsetIndices<int> triangle_offsets = this->triangle_offsets();
443 this->runtime->triangles_cache.ensure([&](Vector<uint3> &r_data) {
444 const int total_triangles = triangle_offsets.total_size();
445 r_data.resize(total_triangles);
446
447 update_triangle_cache(curves.evaluated_positions(),
448 this->curve_plane_normals(),
449 curves.evaluated_points_by_curve(),
450 triangle_offsets,
451 curves.curves_range(),
452 r_data.as_mutable_span());
453 });
454
455 return this->runtime->triangles_cache.data().as_span();
456}
457
459 const OffsetIndices<int> points_by_curve,
460 const IndexMask &curve_mask,
461 MutableSpan<float3> normals)
462{
463 curve_mask.foreach_index(GrainSize(512), [&](const int curve_i) {
464 const IndexRange points = points_by_curve[curve_i];
465 if (points.size() < 2) {
466 normals[curve_i] = float3(1.0f, 0.0f, 0.0f);
467 return;
468 }
469
470 /* Calculate normal using Newell's method. */
471 float3 normal(0.0f);
472 float3 prev_point = positions[points.last()];
473 for (const int point_i : points) {
474 const float3 curr_point = positions[point_i];
475 add_newell_cross_v3_v3v3(normal, prev_point, curr_point);
476 prev_point = curr_point;
477 }
478
479 float length;
480 normal = math::normalize_and_get_length(normal, length);
481 /* Check for degenerate case where the points are on a line. */
482 if (math::is_zero(length)) {
483 for (const int point_i : points.drop_back(1)) {
484 float3 segment_vec = positions[point_i] - positions[point_i + 1];
485 if (math::length_squared(segment_vec) != 0.0f) {
486 normal = math::normalize(float3(segment_vec.y, -segment_vec.x, 0.0f));
487 break;
488 }
489 }
490 }
491
492 normals[curve_i] = normal;
493 });
494}
495
497{
498 this->runtime->curve_plane_normals_cache.ensure([&](Vector<float3> &r_data) {
499 const CurvesGeometry &curves = this->strokes();
500 r_data.reinitialize(curves.curves_num());
501 update_curve_plane_normal_cache(curves.positions(),
502 curves.points_by_curve(),
503 curves.curves_range(),
504 r_data.as_mutable_span());
505 });
506 return this->runtime->curve_plane_normals_cache.data().as_span();
507}
508
509/*
510 * Returns the matrix that transforms from a 3D point in layer-space to a 2D point in
511 * stroke-space for the stroke `curve_i`
512 */
513static float4x2 get_local_to_stroke_matrix(const Span<float3> positions, const float3 normal)
514{
515 using namespace blender::math;
516
517 if (positions.size() <= 2) {
518 return float4x2::identity();
519 }
520
521 const float3 point_0 = positions[0];
522 const float3 point_1 = positions[1];
523
524 /* Local X axis (p0 -> p1) */
525 const float3 local_x = normalize(point_1 - point_0);
526 /* Local Y axis (cross to normal/x axis). */
527 const float3 local_y = normalize(cross(normal, local_x));
528
529 if (length_squared(local_x) == 0.0f || length_squared(local_y) == 0.0f) {
530 return float4x2::identity();
531 }
532
533 /* Get local space using first point as origin. */
534 const float4x2 mat = transpose(
535 float2x4(float4(local_x, -dot(point_0, local_x)), float4(local_y, -dot(point_0, local_y))));
536
537 return mat;
538}
539
540/*
541 * Returns the matrix that transforms from a 2D point in stroke-space to a 2D point in
542 * texture-space for a stroke `curve_i`
543 */
544static float3x2 get_stroke_to_texture_matrix(const float uv_rotation,
545 const float2 uv_translation,
546 const float2 uv_scale)
547{
548 using namespace blender::math;
549
550 const float2 uv_scale_inv = safe_rcp(uv_scale);
551 const float s = sin(uv_rotation);
552 const float c = cos(uv_rotation);
553 const float2x2 rot = float2x2(float2(c, s), float2(-s, c));
554
555 float3x2 texture_matrix = float3x2::identity();
556 /*
557 * The order in which the three transforms are applied has been carefully chosen to be easy to
558 * invert.
559 *
560 * The translation is applied last so that the origin goes to `uv_translation`
561 * The rotation is applied after the scale so that the `u` direction's angle is `uv_rotation`
562 * Scale is the only transform that changes the length of the basis vectors and if it is applied
563 * first it's independent of the other transforms.
564 *
565 * These properties are not true with a different order.
566 */
567
568 /* Apply scale. */
569 texture_matrix = from_scale<float2x2>(uv_scale_inv) * texture_matrix;
570
571 /* Apply rotation. */
572 texture_matrix = rot * texture_matrix;
573
574 /* Apply translation. */
575 texture_matrix[2] += uv_translation;
576
577 return texture_matrix;
578}
579
581{
582 float4x3 strokemat4x3 = float4x3(strokemat);
583
584 /*
585 * We need the diagonal of ones to start from the bottom right instead top left to properly
586 * apply the two matrices.
587 *
588 * i.e.
589 * # # # # # # # #
590 * We need # # # # Instead of # # # #
591 * 0 0 0 1 0 0 1 0
592 *
593 */
594 strokemat4x3[2][2] = 0.0f;
595 strokemat4x3[3][2] = 1.0f;
596
597 return strokemat4x3;
598}
599
601{
602 this->runtime->curve_texture_matrices.ensure([&](Vector<float4x2> &r_data) {
603 const CurvesGeometry &curves = this->strokes();
604 const AttributeAccessor attributes = curves.attributes();
605
606 const VArray<float> uv_rotations = *attributes.lookup_or_default<float>(
607 "uv_rotation", AttrDomain::Curve, 0.0f);
608 const VArray<float2> uv_translations = *attributes.lookup_or_default<float2>(
609 "uv_translation", AttrDomain::Curve, float2(0.0f, 0.0f));
610 const VArray<float2> uv_scales = *attributes.lookup_or_default<float2>(
611 "uv_scale", AttrDomain::Curve, float2(1.0f, 1.0f));
612
613 const OffsetIndices<int> points_by_curve = curves.points_by_curve();
614 const Span<float3> positions = curves.positions();
615 const Span<float3> normals = this->curve_plane_normals();
616
617 r_data.reinitialize(curves.curves_num());
618 threading::parallel_for(curves.curves_range(), 512, [&](const IndexRange range) {
619 for (const int curve_i : range) {
620 const IndexRange points = points_by_curve[curve_i];
621 const float3 normal = normals[curve_i];
622 const float4x2 strokemat = get_local_to_stroke_matrix(positions.slice(points), normal);
623 const float3x2 texture_matrix = get_stroke_to_texture_matrix(
624 uv_rotations[curve_i], uv_translations[curve_i], uv_scales[curve_i]);
625
626 const float4x2 texspace = texture_matrix * expand_4x2_mat(strokemat);
627
628 r_data[curve_i] = texspace;
629 }
630 });
631 });
632 return this->runtime->curve_texture_matrices.data().as_span();
633}
634
636{
637 using namespace blender::math;
638 CurvesGeometry &curves = this->strokes_for_write();
639 MutableAttributeAccessor attributes = curves.attributes_for_write();
640 SpanAttributeWriter<float> uv_rotations = attributes.lookup_or_add_for_write_span<float>(
641 "uv_rotation", AttrDomain::Curve);
642 SpanAttributeWriter<float2> uv_translations = attributes.lookup_or_add_for_write_span<float2>(
643 "uv_translation", AttrDomain::Curve);
644 SpanAttributeWriter<float2> uv_scales = attributes.lookup_or_add_for_write_span<float2>(
645 "uv_scale",
647 AttributeInitVArray(VArray<float2>::ForSingle(float2(1.0f, 1.0f), curves.curves_num())));
648
649 const OffsetIndices<int> points_by_curve = curves.points_by_curve();
650 const Span<float3> positions = curves.positions();
651 const Span<float3> normals = this->curve_plane_normals();
652
653 selection.foreach_index(GrainSize(256), [&](const int64_t curve_i, const int64_t pos) {
654 const IndexRange points = points_by_curve[curve_i];
655 const float3 normal = normals[curve_i];
656 const float4x2 strokemat = get_local_to_stroke_matrix(positions.slice(points), normal);
657 const float4x2 texspace = matrices[pos];
658
659 /* We do the computation using doubles to avoid numerical precision errors. */
660 const double4x3 strokemat4x3 = double4x3(expand_4x2_mat(strokemat));
661
662 /*
663 * We want to solve for `texture_matrix` in the equation: `texspace = texture_matrix *
664 * strokemat4x3` Because these matrices are not square we can not use a standard inverse.
665 *
666 * Our problem has the form of: `X = A * Y`
667 * We can solve for `A` using: `A = X * B`
668 *
669 * Where `B` is the Right-sided inverse or Moore-Penrose pseudo inverse.
670 * Calculated as:
671 *
672 * |--------------------------|
673 * | B = T(Y) * (Y * T(Y))^-1 |
674 * |--------------------------|
675 *
676 * And `T()` is transpose and `()^-1` is the inverse.
677 */
678
679 const double3x4 transpose_strokemat = transpose(strokemat4x3);
680 const double3x4 right_inverse = transpose_strokemat *
681 invert(strokemat4x3 * transpose_strokemat);
682
683 const float3x2 texture_matrix = float3x2(double4x2(texspace) * right_inverse);
684
685 /* Solve for translation, the translation is simply the origin. */
686 const float2 uv_translation = texture_matrix[2];
687
688 /* Solve rotation, the angle of the `u` basis is the rotation. */
689 const float uv_rotation = atan2(texture_matrix[0][1], texture_matrix[0][0]);
690
691 /* Calculate the determinant to check if the `v` scale is negative. */
692 const float det = determinant(float2x2(texture_matrix));
693
694 /* Solve scale, scaling is the only transformation that changes the length, so scale factor
695 * is simply the length. And flip the sign of `v` if the determinant is negative. */
696 const float2 uv_scale = safe_rcp(
697 float2(length(texture_matrix[0]), sign(det) * length(texture_matrix[1])));
698
699 uv_rotations.span[curve_i] = uv_rotation;
700 uv_translations.span[curve_i] = uv_translation;
701 uv_scales.span[curve_i] = uv_scale;
702 });
703 uv_rotations.finish();
704 uv_translations.finish();
705 uv_scales.finish();
706
707 this->tag_texture_matrices_changed();
708}
709
711{
712 return this->geometry.wrap();
713}
714
716{
717 return this->geometry.wrap();
718}
719
721{
722 return *this->strokes().attributes().lookup_or_default<float>(
724}
725
727{
729 this->strokes_for_write(), AttrDomain::Point, ATTR_RADIUS, 0.01f);
730}
731
733{
734 return *this->strokes().attributes().lookup_or_default<float>(
736}
737
743
745{
746 return *this->strokes().attributes().lookup_or_default<ColorGeometry4f>(
747 ATTR_VERTEX_COLOR, AttrDomain::Point, ColorGeometry4f(0.0f, 0.0f, 0.0f, 0.0f));
748}
749
757
759{
760 return *this->strokes().attributes().lookup_or_default<ColorGeometry4f>(
761 ATTR_FILL_COLOR, AttrDomain::Curve, ColorGeometry4f(0.0f, 0.0f, 0.0f, 0.0f));
762}
763
771
773{
774 this->runtime->curve_texture_matrices.tag_dirty();
775}
776
778{
779 this->strokes_for_write().tag_positions_changed();
780 this->runtime->curve_plane_normals_cache.tag_dirty();
781 this->runtime->triangles_cache.tag_dirty();
782 this->tag_texture_matrices_changed();
783}
784
785void Drawing::tag_positions_changed(const IndexMask &changed_curves)
786{
787 if (changed_curves.is_empty()) {
788 return;
789 }
790 /* If more than half of the curves have changed, update the entire cache instead.
791 * The assumption here is that it's better to lazily compute the caches if more than half of the
792 * curves need to be updated.
793 * TODO: This could probably be a bit more rigorous once this function gets used in more places.
794 */
795 if (changed_curves.size() > this->strokes().curves_num() / 2) {
796 this->tag_positions_changed();
797 return;
798 }
799 if (!this->runtime->triangles_cache.is_cached() ||
800 !this->runtime->curve_plane_normals_cache.is_cached())
801 {
802 this->tag_positions_changed();
803 return;
804 }
805 /* Positions needs to be tagged first, because the triangle cache updates just after need the
806 * positions to be up-to-date. */
807 this->strokes_for_write().tag_positions_changed();
808 this->runtime->curve_plane_normals_cache.update([&](Vector<float3> &normals) {
809 const CurvesGeometry &curves = this->strokes();
811 curves.positions(), curves.points_by_curve(), changed_curves, normals);
812 });
813 this->runtime->triangles_cache.update([&](Vector<uint3> &triangles) {
814 const CurvesGeometry &curves = this->strokes();
815 update_triangle_cache(curves.evaluated_positions(),
816 this->curve_plane_normals(),
817 curves.evaluated_points_by_curve(),
818 this->triangle_offsets(),
819 curves.curves_range(),
820 triangles);
821 });
822 this->tag_texture_matrices_changed();
823}
824
826{
827 this->runtime->triangle_offsets_cache.tag_dirty();
828 this->tag_positions_changed();
829 this->strokes_for_write().tag_topology_changed();
830}
831
832void Drawing::tag_topology_changed(const IndexMask &changed_curves)
833{
834 if (changed_curves.is_empty()) {
835 return;
836 }
837 /* If more than half of the curves have changed, update the entire cache instead.
838 * The assumption here is that it's better to lazily compute the caches if more than half of the
839 * curves need to be updated.
840 * TODO: This could probably be a bit more rigorous once this function gets used in more places.
841 */
842 if (changed_curves.size() > this->strokes().curves_num() / 2) {
843 this->tag_topology_changed();
844 return;
845 }
846 if (!this->runtime->triangles_cache.is_cached() ||
847 !this->runtime->curve_plane_normals_cache.is_cached())
848 {
849 this->tag_topology_changed();
850 return;
851 }
852 /* Positions needs to be tagged first, because the triangle cache updates just after need the
853 * positions to be up-to-date. */
854 this->strokes_for_write().tag_positions_changed();
855 this->runtime->curve_plane_normals_cache.update([&](Vector<float3> &normals) {
856 const CurvesGeometry &curves = this->strokes();
858 curves.positions(), curves.points_by_curve(), changed_curves, normals);
859 });
860 /* Copy the current triangle offsets. These are used to copy over the triangle data for curves
861 * that don't need to be updated. */
862 const Array<int> src_triangle_offset_data(this->triangle_offsets().data());
863 const OffsetIndices<int> src_triangle_offsets = src_triangle_offset_data.as_span();
864 /* Tag the `triangle_offsets_cache` so that the `triangles_cache` update can use the up-to-date
865 * triangle offsets. */
866 this->runtime->triangle_offsets_cache.tag_dirty();
867
868 this->runtime->triangles_cache.update([&](Vector<uint3> &triangles) {
869 const CurvesGeometry &curves = this->strokes();
870 const OffsetIndices<int> dst_triangle_offsets = this->triangle_offsets();
871
872 IndexMaskMemory memory;
873 const IndexMask curves_to_copy = changed_curves.complement(curves.curves_range(), memory);
874
875 const Vector<uint3> src_triangles(triangles);
876 triangles.reinitialize(dst_triangle_offsets.total_size());
877 /* Copy groups to groups. */
878 curves_to_copy.foreach_index(GrainSize(1024), [&](const int i) {
879 triangles.as_mutable_span()
880 .slice(dst_triangle_offsets[i])
881 .copy_from(src_triangles.as_span().slice(src_triangle_offsets[i]));
882 });
883
884 update_triangle_cache(curves.evaluated_positions(),
885 this->curve_plane_normals(),
886 curves.evaluated_points_by_curve(),
887 dst_triangle_offsets,
888 changed_curves,
889 triangles);
890 });
891 this->tag_texture_matrices_changed();
892}
893
894DrawingReference::DrawingReference()
895{
896 this->base.type = GP_DRAWING_REFERENCE;
897 this->base.flag = 0;
898
899 this->id_reference = nullptr;
900}
901
902DrawingReference::DrawingReference(const DrawingReference &other)
903{
904 this->base.type = GP_DRAWING_REFERENCE;
905 this->base.flag = other.base.flag;
906
907 this->id_reference = other.id_reference;
908}
909
910DrawingReference::~DrawingReference() = default;
911
914{
915 BLI_assert(src_drawings.size() == dst_drawings.size());
916 for (const int i : src_drawings.index_range()) {
917 const GreasePencilDrawingBase *src_drawing_base = src_drawings[i];
918 switch (src_drawing_base->type) {
919 case GP_DRAWING: {
920 const GreasePencilDrawing *src_drawing = reinterpret_cast<const GreasePencilDrawing *>(
921 src_drawing_base);
922 dst_drawings[i] = reinterpret_cast<GreasePencilDrawingBase *>(
923 MEM_new<bke::greasepencil::Drawing>(__func__, src_drawing->wrap()));
924 break;
925 }
927 const GreasePencilDrawingReference *src_drawing_reference =
928 reinterpret_cast<const GreasePencilDrawingReference *>(src_drawing_base);
929 dst_drawings[i] = reinterpret_cast<GreasePencilDrawingBase *>(
930 MEM_new<bke::greasepencil::DrawingReference>(__func__, src_drawing_reference->wrap()));
931 break;
932 }
933 }
934 }
935}
936
937TreeNode::TreeNode()
938{
939 this->next = this->prev = nullptr;
940 this->parent = nullptr;
941
942 this->GreasePencilLayerTreeNode::name = nullptr;
943 this->flag = 0;
944 this->color[0] = this->color[1] = this->color[2] = 0;
945}
946
947TreeNode::TreeNode(GreasePencilLayerTreeNodeType type) : TreeNode()
948{
949 this->type = type;
950}
951
957
959{
960 this->GreasePencilLayerTreeNode::name = BLI_strdup_null(other.GreasePencilLayerTreeNode::name);
961 this->flag = other.flag;
962 copy_v3_v3_uchar(this->color, other.color);
963}
964
969
970void TreeNode::set_name(StringRefNull name)
971{
974}
975
977{
978 return *reinterpret_cast<const LayerGroup *>(this);
979}
980
982{
983 return *reinterpret_cast<const Layer *>(this);
984}
985
987{
988 return *reinterpret_cast<LayerGroup *>(this);
989}
990
992{
993 return *reinterpret_cast<Layer *>(this);
994}
995
997{
998 return (this->parent) ? &this->parent->wrap() : nullptr;
999}
1001{
1002 return (this->parent) ? &this->parent->wrap() : nullptr;
1003}
1005{
1006 return this->parent_group() ? &this->parent->wrap().as_node() : nullptr;
1007}
1009{
1010 return this->parent_group() ? &this->parent->wrap().as_node() : nullptr;
1011}
1012
1014{
1015 const LayerGroup *parent = this->parent_group();
1016 if (parent == nullptr) {
1017 /* The root group has a depth of 0. */
1018 return 0;
1019 }
1020 return 1 + parent->as_node().depth();
1021}
1022
1024{
1025 this->layer_name = nullptr;
1026 this->flag = 0;
1027}
1028
1033
1035{
1036 this->layer_name = BLI_strdup_null(other.layer_name);
1037 this->flag = other.flag;
1038}
1039
1041{
1042 if (this->layer_name) {
1043 MEM_freeN(this->layer_name);
1044 }
1045}
1046
1048{
1050 sorted_keys_cache_.tag_dirty();
1051 masks_.clear_and_shrink();
1052 trans_data_ = {};
1053}
1054
1056{
1057 new (&this->base) TreeNode(GP_LAYER_TREE_LEAF);
1058
1059 this->frames_storage.num = 0;
1060 this->frames_storage.keys = nullptr;
1061 this->frames_storage.values = nullptr;
1062 this->frames_storage.flag = 0;
1063
1065 this->opacity = 1.0f;
1066
1067 this->parent = nullptr;
1068 this->parsubstr = nullptr;
1069 unit_m4(this->parentinv);
1070
1071 zero_v3(this->translation);
1072 zero_v3(this->rotation);
1073 copy_v3_fl(this->scale, 1.0f);
1074
1075 this->viewlayername = nullptr;
1076
1077 BLI_listbase_clear(&this->masks);
1078 this->active_mask_index = 0;
1079
1080 this->runtime = MEM_new<LayerRuntime>(__func__);
1081}
1082
1084{
1085 new (&this->base) TreeNode(GP_LAYER_TREE_LEAF, name);
1086}
1087
1088Layer::Layer(const Layer &other) : Layer()
1089{
1090 new (&this->base) TreeNode(other.base.wrap());
1091
1092 LISTBASE_FOREACH (GreasePencilLayerMask *, other_mask, &other.masks) {
1093 LayerMask *new_mask = MEM_new<LayerMask>(__func__, *reinterpret_cast<LayerMask *>(other_mask));
1094 BLI_addtail(&this->masks, reinterpret_cast<GreasePencilLayerMask *>(new_mask));
1095 }
1097
1098 this->blend_mode = other.blend_mode;
1099 this->opacity = other.opacity;
1100
1101 this->parent = other.parent;
1102 this->set_parent_bone_name(other.parsubstr);
1103 copy_m4_m4(this->parentinv, other.parentinv);
1104
1105 copy_v3_v3(this->translation, other.translation);
1106 copy_v3_v3(this->rotation, other.rotation);
1107 copy_v3_v3(this->scale, other.scale);
1108
1110
1111 /* NOTE: We do not duplicate the frame storage since it is only needed for writing to file. */
1112 this->runtime->frames_ = other.runtime->frames_;
1113 this->runtime->sorted_keys_cache_ = other.runtime->sorted_keys_cache_;
1114 /* Tag the frames map, so the frame storage is recreated once the DNA is saved. */
1115 this->tag_frames_map_changed();
1116
1117 /* TODO: what about masks cache? */
1118}
1119
1121{
1122 this->base.wrap().~TreeNode();
1123
1126
1127 LISTBASE_FOREACH_MUTABLE (GreasePencilLayerMask *, mask, &this->masks) {
1128 MEM_delete(reinterpret_cast<LayerMask *>(mask));
1129 }
1130 BLI_listbase_clear(&this->masks);
1131
1132 MEM_SAFE_FREE(this->parsubstr);
1134
1135 MEM_delete(this->runtime);
1136 this->runtime = nullptr;
1137}
1138
1140{
1141 return this->runtime->frames_;
1142}
1143
1145{
1146 return this->runtime->frames_;
1147}
1148
1149Layer::SortedKeysIterator Layer::remove_leading_end_frames_in_range(
1151{
1152 Layer::SortedKeysIterator next_it = begin;
1153 while (next_it != end && this->frames().lookup(*next_it).is_end()) {
1154 this->frames_for_write().remove_contained(*next_it);
1156 next_it = std::next(next_it);
1157 }
1158 return next_it;
1159}
1160
1161GreasePencilFrame *Layer::add_frame_internal(const FramesMapKeyT frame_number)
1162{
1163 if (!this->frames().contains(frame_number)) {
1164 GreasePencilFrame frame{};
1165 this->frames_for_write().add_new(frame_number, frame);
1167 return this->frames_for_write().lookup_ptr(frame_number);
1168 }
1169 /* Overwrite end-frames. */
1170 if (this->frames().lookup(frame_number).is_end()) {
1171 GreasePencilFrame frame{};
1172 this->frames_for_write().add_overwrite(frame_number, frame);
1173 this->tag_frames_map_changed();
1174 return this->frames_for_write().lookup_ptr(frame_number);
1175 }
1176 return nullptr;
1177}
1178
1179GreasePencilFrame *Layer::add_frame(const FramesMapKeyT key, const int duration)
1180{
1181 BLI_assert(duration >= 0);
1182 GreasePencilFrame *frame = this->add_frame_internal(key);
1183 if (frame == nullptr) {
1184 return nullptr;
1185 }
1187 const FramesMapKeyT end_key = key + duration;
1188 /* Finds the next greater key that is stored in the map. */
1189 SortedKeysIterator next_key_it = std::upper_bound(sorted_keys.begin(), sorted_keys.end(), key);
1190 /* If the next frame we found is at the end of the frame we're inserting, then we are done. */
1191 if (next_key_it != sorted_keys.end() && *next_key_it == end_key) {
1192 return frame;
1193 }
1194 next_key_it = this->remove_leading_end_frames_in_range(next_key_it, sorted_keys.end());
1195 /* If the duration is set to 0, the frame is marked as an implicit hold. */
1196 if (duration == 0) {
1197 frame->flag |= GP_FRAME_IMPLICIT_HOLD;
1198 return frame;
1199 }
1200 /* If the next frame comes after the end of the frame we're inserting (or if there are no more
1201 * frames), add an end-frame. */
1202 if (next_key_it == sorted_keys.end() || *next_key_it > end_key) {
1203 this->frames_for_write().add_new(end_key, GreasePencilFrame::end());
1205 }
1206 return frame;
1207}
1208
1210{
1211 /* If the frame number is not in the frames map, do nothing. */
1212 if (!this->frames().contains(key)) {
1213 return false;
1214 }
1215 if (this->frames().size() == 1) {
1218 return true;
1219 }
1221 /* Find the index of the frame to remove in the `sorted_keys` array. */
1222 SortedKeysIterator remove_key_it = std::lower_bound(sorted_keys.begin(), sorted_keys.end(), key);
1223 /* If there is a next frame: */
1224 if (std::next(remove_key_it) != sorted_keys.end()) {
1225 SortedKeysIterator next_key_it = std::next(remove_key_it);
1226 this->remove_leading_end_frames_in_range(next_key_it, sorted_keys.end());
1227 }
1228 /* If there is a previous frame: */
1229 if (remove_key_it != sorted_keys.begin()) {
1230 SortedKeysIterator prev_key_it = std::prev(remove_key_it);
1231 const GreasePencilFrame &prev_frame = this->frames().lookup(*prev_key_it);
1232 /* If the previous frame is not an implicit hold (e.g. it has a fixed duration) and it's not an
1233 * end frame, we cannot just delete the frame. We need to replace it with an end frame. */
1234 if (!prev_frame.is_implicit_hold() && !prev_frame.is_end()) {
1235 this->frames_for_write().lookup(key) = GreasePencilFrame::end();
1236 this->tag_frames_map_changed();
1237 /* Since the original frame was replaced with an end frame, we consider the frame to be
1238 * successfully removed here. */
1239 return true;
1240 }
1241 }
1242 /* Finally, remove the actual frame. */
1245 return true;
1246}
1247
1249{
1250 this->runtime->sorted_keys_cache_.ensure([&](Vector<FramesMapKeyT> &r_data) {
1251 r_data.reinitialize(this->frames().size());
1252 int i = 0;
1253 for (const FramesMapKeyT key : this->frames().keys()) {
1254 r_data[i++] = key;
1255 }
1256 std::sort(r_data.begin(), r_data.end());
1257 });
1258 return this->runtime->sorted_keys_cache_.data();
1259}
1260
1262{
1264 /* No keyframes, return nullptr. */
1265 if (sorted_keys.is_empty()) {
1266 return nullptr;
1267 }
1268 /* Before the first frame, return nullptr. */
1269 if (frame_number < sorted_keys.first()) {
1270 return nullptr;
1271 }
1272 /* After or at the last frame, return iterator to last. */
1273 if (frame_number >= sorted_keys.last()) {
1274 return std::prev(sorted_keys.end());
1275 }
1276 /* Search for the frame. std::upper_bound will get the frame just after. */
1277 SortedKeysIterator it = std::upper_bound(sorted_keys.begin(), sorted_keys.end(), frame_number);
1278 if (it == sorted_keys.end()) {
1279 return nullptr;
1280 }
1281 return std::prev(it);
1282}
1283
1284std::optional<FramesMapKeyT> Layer::frame_key_at(const int frame_number) const
1285{
1286 SortedKeysIterator it = this->sorted_keys_iterator_at(frame_number);
1287 if (it == nullptr) {
1288 return {};
1289 }
1290 return *it;
1291}
1292
1293std::optional<int> Layer::start_frame_at(int frame_number) const
1294{
1295 const std::optional<FramesMapKeyT> frame_key = this->frame_key_at(frame_number);
1296 /* Return the frame number only if the frame key exists and if it's not an end frame. */
1297 if (frame_key && !this->frames().lookup_ptr(*frame_key)->is_end()) {
1298 return *frame_key;
1299 }
1300 return {};
1301}
1302
1303int Layer::sorted_keys_index_at(const int frame_number) const
1304{
1305 SortedKeysIterator it = this->sorted_keys_iterator_at(frame_number);
1306 if (it == nullptr) {
1307 return -1;
1308 }
1309 return std::distance(this->sorted_keys().begin(), it);
1310}
1311
1312const GreasePencilFrame *Layer::frame_at(const int frame_number) const
1313{
1314 const GreasePencilFrame *frame_ptr = [&]() -> const GreasePencilFrame * {
1315 if (const GreasePencilFrame *frame = this->frames().lookup_ptr(frame_number)) {
1316 return frame;
1317 }
1318 /* Look for a keyframe that starts before `frame_number` and ends after `frame_number`. */
1319 const std::optional<FramesMapKeyT> frame_key = this->frame_key_at(frame_number);
1320 if (!frame_key) {
1321 return nullptr;
1322 }
1323 return this->frames().lookup_ptr(*frame_key);
1324 }();
1325 if (frame_ptr == nullptr || frame_ptr->is_end()) {
1326 /* Not a valid frame. */
1327 return nullptr;
1328 }
1329 return frame_ptr;
1330}
1331
1332GreasePencilFrame *Layer::frame_at(const int frame_number)
1333{
1334 GreasePencilFrame *frame_ptr = [&]() -> GreasePencilFrame * {
1335 if (GreasePencilFrame *frame = this->frames_for_write().lookup_ptr(frame_number)) {
1336 return frame;
1337 }
1338 /* Look for a keyframe that starts before `frame_number`. */
1339 const std::optional<FramesMapKeyT> frame_key = this->frame_key_at(frame_number);
1340 if (!frame_key) {
1341 return nullptr;
1342 }
1343 return this->frames_for_write().lookup_ptr(*frame_key);
1344 }();
1345 if (frame_ptr == nullptr || frame_ptr->is_end()) {
1346 /* Not a valid frame. */
1347 return nullptr;
1348 }
1349 return frame_ptr;
1350}
1351
1352int Layer::drawing_index_at(const int frame_number) const
1353{
1354 const GreasePencilFrame *frame = frame_at(frame_number);
1355 return (frame != nullptr) ? frame->drawing_index : -1;
1356}
1357
1358bool Layer::has_drawing_at(const int frame_number) const
1359{
1360 return frame_at(frame_number) != nullptr;
1361}
1362
1363int Layer::get_frame_duration_at(const int frame_number) const
1364{
1365 SortedKeysIterator it = this->sorted_keys_iterator_at(frame_number);
1366 if (it == nullptr) {
1367 return -1;
1368 }
1369 const FramesMapKeyT key = *it;
1370 const GreasePencilFrame *frame = this->frames().lookup_ptr(key);
1371 /* For frames that are implicitly held, we return a duration of 0. */
1372 if (frame->is_implicit_hold()) {
1373 return 0;
1374 }
1375 /* Frame is an end frame, so there is no keyframe at `frame_number`. */
1376 if (frame->is_end()) {
1377 return -1;
1378 }
1379 /* Compute the distance in frames between this key and the next key. */
1380 const int next_frame_number = *(std::next(it));
1381 return math::distance(key, next_frame_number);
1382}
1383
1388
1390{
1391 this->tag_frames_map_changed();
1392 this->runtime->sorted_keys_cache_.tag_dirty();
1393}
1394
1396{
1397 /* Re-create the frames storage only if it was tagged dirty. */
1399 return;
1400 }
1401
1404
1405 const size_t frames_num = size_t(frames().size());
1406 frames_storage.num = int(frames_num);
1407 frames_storage.keys = MEM_cnew_array<int>(frames_num, __func__);
1408 frames_storage.values = MEM_cnew_array<GreasePencilFrame>(frames_num, __func__);
1409 const Span<int> sorted_keys_data = sorted_keys();
1410 for (const int64_t i : sorted_keys_data.index_range()) {
1411 frames_storage.keys[i] = sorted_keys_data[i];
1412 frames_storage.values[i] = frames().lookup(sorted_keys_data[i]);
1413 }
1414
1415 /* Reset the flag. */
1416 frames_storage.flag &= ~GP_LAYER_FRAMES_STORAGE_DIRTY;
1417}
1418
1420{
1421 /* Re-create frames data in runtime map. */
1422 /* NOTE: Avoid re-allocating runtime data to reduce 'false positive' change detections from
1423 * memfile undo. */
1424 if (runtime) {
1425 runtime->clear();
1426 }
1427 else {
1428 runtime = MEM_new<blender::bke::greasepencil::LayerRuntime>(__func__);
1429 }
1431 for (int i = 0; i < frames_storage.num; i++) {
1432 frames.add_new(frames_storage.keys[i], frames_storage.values[i]);
1433 }
1434}
1435
1437{
1438 if (this->parent == nullptr) {
1439 return object.object_to_world() * this->local_transform();
1440 }
1441 const Object &parent = *this->parent;
1442 return this->parent_to_world(parent) * this->parent_inverse() * this->local_transform();
1443}
1444
1446{
1447 if (this->parent == nullptr) {
1448 return this->local_transform();
1449 }
1450 const Object &parent = *this->parent;
1451 return object.world_to_object() * this->parent_to_world(parent) * this->parent_inverse() *
1452 this->local_transform();
1453}
1454
1456{
1457 return (this->parsubstr != nullptr) ? StringRefNull(this->parsubstr) : StringRefNull();
1458}
1459
1460void Layer::set_parent_bone_name(const char *new_name)
1461{
1462 if (this->parsubstr != nullptr) {
1463 MEM_freeN(this->parsubstr);
1464 }
1465 this->parsubstr = BLI_strdup_null(new_name);
1466}
1467
1468float4x4 Layer::parent_to_world(const Object &parent) const
1469{
1470 const float4x4 &parent_object_to_world = parent.object_to_world();
1471 if (parent.type == OB_ARMATURE && !this->parent_bone_name().is_empty()) {
1473 this->parent_bone_name().c_str()))
1474 {
1475 return parent_object_to_world * float4x4_view(channel->pose_mat);
1476 }
1477 }
1478 return parent_object_to_world;
1479}
1480
1482{
1483 return float4x4_view(this->parentinv);
1484}
1485
1487{
1489 float3(this->translation), float3(this->rotation), float3(this->scale));
1490}
1491
1493{
1495 *reinterpret_cast<float3 *>(this->translation),
1496 *reinterpret_cast<math::EulerXYZ *>(this->rotation),
1497 *reinterpret_cast<float3 *>(this->scale));
1498}
1499
1501{
1502 return (this->viewlayername != nullptr) ? StringRefNull(this->viewlayername) : StringRefNull();
1503}
1504
1505void Layer::set_view_layer_name(const char *new_name)
1506{
1507 if (this->viewlayername != nullptr) {
1508 MEM_freeN(this->viewlayername);
1509 }
1510 this->viewlayername = BLI_strdup_null(new_name);
1511}
1512
1514{
1515 new (&this->base) TreeNode(GP_LAYER_TREE_GROUP);
1516
1519
1520 this->runtime = MEM_new<LayerGroupRuntime>(__func__);
1521}
1522
1524{
1525 new (&this->base) TreeNode(GP_LAYER_TREE_GROUP, name);
1526}
1527
1529{
1530 new (&this->base) TreeNode(other.base.wrap());
1531
1532 LISTBASE_FOREACH (GreasePencilLayerTreeNode *, child, &other.children) {
1533 switch (child->type) {
1534 case GP_LAYER_TREE_LEAF: {
1535 GreasePencilLayer *layer = reinterpret_cast<GreasePencilLayer *>(child);
1536 Layer *dup_layer = MEM_new<Layer>(__func__, layer->wrap());
1537 this->add_node(dup_layer->as_node());
1538 break;
1539 }
1540 case GP_LAYER_TREE_GROUP: {
1541 GreasePencilLayerTreeGroup *group = reinterpret_cast<GreasePencilLayerTreeGroup *>(child);
1542 LayerGroup *dup_group = MEM_new<LayerGroup>(__func__, group->wrap());
1543 this->add_node(dup_group->as_node());
1544 break;
1545 }
1546 }
1547 }
1548
1549 this->color_tag = other.color_tag;
1550}
1551
1553{
1554 this->base.wrap().~TreeNode();
1555
1557 switch (child->type) {
1558 case GP_LAYER_TREE_LEAF: {
1559 GreasePencilLayer *layer = reinterpret_cast<GreasePencilLayer *>(child);
1560 MEM_delete(&layer->wrap());
1561 break;
1562 }
1563 case GP_LAYER_TREE_GROUP: {
1564 GreasePencilLayerTreeGroup *group = reinterpret_cast<GreasePencilLayerTreeGroup *>(child);
1565 MEM_delete(&group->wrap());
1566 break;
1567 }
1568 }
1569 }
1570
1571 MEM_delete(this->runtime);
1572 this->runtime = nullptr;
1573}
1574
1576{
1577 if (this == &other) {
1578 return *this;
1579 }
1580
1581 this->~LayerGroup();
1582 new (this) LayerGroup(other);
1583
1584 return *this;
1585}
1586
1588{
1589 BLI_addtail(&this->children, &node);
1590 node.parent = reinterpret_cast<GreasePencilLayerTreeGroup *>(this);
1591 this->tag_nodes_cache_dirty();
1592 return node;
1593}
1595{
1596 BLI_assert(BLI_findindex(&this->children, &link) != -1);
1597 BLI_insertlinkbefore(&this->children, &link, &node);
1598 node.parent = reinterpret_cast<GreasePencilLayerTreeGroup *>(this);
1599 this->tag_nodes_cache_dirty();
1600}
1602{
1603 BLI_assert(BLI_findindex(&this->children, &link) != -1);
1604 BLI_insertlinkafter(&this->children, &link, &node);
1605 node.parent = reinterpret_cast<GreasePencilLayerTreeGroup *>(this);
1606 this->tag_nodes_cache_dirty();
1607}
1608
1609void LayerGroup::move_node_up(TreeNode &node, const int step)
1610{
1611 BLI_listbase_link_move(&this->children, &node, step);
1612 this->tag_nodes_cache_dirty();
1613}
1614void LayerGroup::move_node_down(TreeNode &node, const int step)
1615{
1616 BLI_listbase_link_move(&this->children, &node, -step);
1617 this->tag_nodes_cache_dirty();
1618}
1620{
1621 BLI_remlink(&this->children, &node);
1622 BLI_insertlinkafter(&this->children, this->children.last, &node);
1623 this->tag_nodes_cache_dirty();
1624}
1626{
1627 BLI_remlink(&this->children, &node);
1628 BLI_insertlinkbefore(&this->children, this->children.first, &node);
1629 this->tag_nodes_cache_dirty();
1630}
1631
1633{
1634 return BLI_listbase_count(&this->children);
1635}
1636
1638{
1639 this->ensure_nodes_cache();
1640 return this->runtime->nodes_cache_.size();
1641}
1642
1643bool LayerGroup::unlink_node(TreeNode &link, const bool keep_children)
1644{
1645 if (link.is_group() && !link.as_group().is_empty() && keep_children) {
1646 if (BLI_findindex(&this->children, &link) == -1) {
1647 return false;
1648 }
1649
1650 /* Take ownership of the children of `link` by replacing the node with the listbase of its
1651 * children. */
1652 ListBase link_children = link.as_group().children;
1654 link_children.first);
1655 GreasePencilLayerTreeNode *last = static_cast<GreasePencilLayerTreeNode *>(link_children.last);
1656
1657 /* Rewrite the parent pointers. */
1658 LISTBASE_FOREACH (GreasePencilLayerTreeNode *, child, &link_children) {
1659 child->parent = this;
1660 }
1661
1662 /* Update previous and/or next link(s). */
1663 if (link.next != nullptr) {
1664 link.next->prev = last;
1665 last->next = link.next;
1666 }
1667 if (link.prev != nullptr) {
1668 link.prev->next = first;
1669 first->prev = link.prev;
1670 }
1671
1672 /* Update first and/or last link(s). */
1673 if (this->children.last == &link) {
1674 this->children.last = last;
1675 }
1676 if (this->children.first == &link) {
1677 this->children.first = first;
1678 }
1679
1680 /* Listbase has been inserted in `this->children` we can clear the pointers in `link`. */
1682 link.parent = nullptr;
1683
1684 this->tag_nodes_cache_dirty();
1685 return true;
1686 }
1687 else if (BLI_remlink_safe(&this->children, &link)) {
1688 link.parent = nullptr;
1689 this->tag_nodes_cache_dirty();
1690 return true;
1691 }
1692 return false;
1693}
1694
1696{
1697 this->ensure_nodes_cache();
1698 return this->runtime->nodes_cache_.as_span();
1699}
1700
1702{
1703 this->ensure_nodes_cache();
1704 return this->runtime->nodes_cache_.as_span();
1705}
1706
1708{
1709 this->ensure_nodes_cache();
1710 return this->runtime->layer_cache_.as_span();
1711}
1712
1714{
1715 this->ensure_nodes_cache();
1716 return this->runtime->layer_cache_.as_span();
1717}
1718
1720{
1721 this->ensure_nodes_cache();
1722 return this->runtime->layer_group_cache_.as_span();
1723}
1724
1726{
1727 this->ensure_nodes_cache();
1728 return this->runtime->layer_group_cache_.as_span();
1729}
1730
1732{
1733 for (const TreeNode *node : this->nodes()) {
1734 if (StringRef(node->name()) == StringRef(name)) {
1735 return node;
1736 }
1737 }
1738 return nullptr;
1739}
1740
1742{
1743 for (TreeNode *node : this->nodes_for_write()) {
1744 if (StringRef(node->name()) == StringRef(name)) {
1745 return node;
1746 }
1747 }
1748 return nullptr;
1749}
1750
1752{
1753 std::cout << header << std::endl;
1756 TreeNode *child = reinterpret_cast<TreeNode *>(child_);
1757 next_node.push(std::make_pair(1, child));
1758 }
1759 while (!next_node.is_empty()) {
1760 auto [indent, node] = next_node.pop();
1761 for (int i = 0; i < indent; i++) {
1762 std::cout << " ";
1763 }
1764 if (node->is_layer()) {
1765 std::cout << node->name();
1766 }
1767 else if (node->is_group()) {
1768 std::cout << node->name() << ": ";
1769 LISTBASE_FOREACH_BACKWARD (GreasePencilLayerTreeNode *, child_, &node->as_group().children) {
1770 TreeNode *child = reinterpret_cast<TreeNode *>(child_);
1771 next_node.push(std::make_pair(indent + 1, child));
1772 }
1773 }
1774 std::cout << std::endl;
1775 }
1776 std::cout << std::endl;
1777}
1778
1779void LayerGroup::ensure_nodes_cache() const
1780{
1781 this->runtime->nodes_cache_mutex_.ensure([&]() {
1782 this->runtime->nodes_cache_.clear_and_shrink();
1783 this->runtime->layer_cache_.clear_and_shrink();
1784 this->runtime->layer_group_cache_.clear_and_shrink();
1785
1787 TreeNode *node = reinterpret_cast<TreeNode *>(child_);
1788 this->runtime->nodes_cache_.append(node);
1789 switch (node->type) {
1790 case GP_LAYER_TREE_LEAF: {
1791 this->runtime->layer_cache_.append(&node->as_layer());
1792 break;
1793 }
1794 case GP_LAYER_TREE_GROUP: {
1795 this->runtime->layer_group_cache_.append(&node->as_group());
1796 for (TreeNode *child : node->as_group().nodes_for_write()) {
1797 this->runtime->nodes_cache_.append(child);
1798 if (child->is_layer()) {
1799 this->runtime->layer_cache_.append(&child->as_layer());
1800 }
1801 else if (child->is_group()) {
1802 this->runtime->layer_group_cache_.append(&child->as_group());
1803 }
1804 }
1805 break;
1806 }
1807 }
1808 }
1809 });
1810}
1811
1812void LayerGroup::tag_nodes_cache_dirty() const
1813{
1814 this->runtime->nodes_cache_mutex_.tag_dirty();
1815 if (this->base.parent) {
1816 this->base.parent->wrap().tag_nodes_cache_dirty();
1817 }
1818}
1819
1821{
1822 LISTBASE_FOREACH (TreeNode *, child, &children) {
1823 switch (child->type) {
1824 case GP_LAYER_TREE_LEAF: {
1825 child->as_layer().prepare_for_dna_write();
1826 break;
1827 }
1828 case GP_LAYER_TREE_GROUP: {
1829 child->as_group().prepare_for_dna_write();
1830 break;
1831 }
1832 }
1833 }
1834}
1835
1837{
1838 LISTBASE_FOREACH (TreeNode *, child, &children) {
1839 switch (child->type) {
1840 case GP_LAYER_TREE_LEAF: {
1841 child->as_layer().update_from_dna_read();
1842 break;
1843 }
1844 case GP_LAYER_TREE_GROUP: {
1845 child->as_group().update_from_dna_read();
1846 break;
1847 }
1848 }
1849 }
1850}
1851
1852} // namespace blender::bke::greasepencil
1853
1854namespace blender::bke {
1855
1858
1859std::optional<Span<float3>> GreasePencilDrawingEditHints::positions() const
1860{
1861 if (!this->positions_data.has_value()) {
1862 return std::nullopt;
1863 }
1864 const int points_num = this->drawing_orig->geometry.wrap().points_num();
1865 return Span(static_cast<const float3 *>(this->positions_data.data), points_num);
1866}
1867
1868std::optional<MutableSpan<float3>> GreasePencilDrawingEditHints::positions_for_write()
1869{
1870 if (!this->positions_data.has_value()) {
1871 return std::nullopt;
1872 }
1873
1874 const int points_num = this->drawing_orig->geometry.wrap().points_num();
1876 if (data.sharing_info->is_mutable()) {
1877 /* If the referenced component is already mutable, return it directly. */
1878 data.sharing_info->tag_ensured_mutable();
1879 }
1880 else {
1881 auto *new_sharing_info = new ImplicitSharedValue<Array<float3>>(*this->positions());
1882 data.sharing_info = ImplicitSharingPtr<>(new_sharing_info);
1883 data.data = new_sharing_info->data.data();
1884 }
1885
1886 return MutableSpan(const_cast<float3 *>(static_cast<const float3 *>(data.data)), points_num);
1887}
1888
1889} // namespace blender::bke
1890
1891/* ------------------------------------------------------------------- */
1896 const char *name)
1897{
1898 return STREQ(name, ATTR_POSITION);
1899}
1900
1901void *BKE_grease_pencil_add(Main *bmain, const char *name)
1902{
1903 GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(BKE_id_new(bmain, ID_GP, name));
1904
1905 return grease_pencil;
1906}
1907
1909{
1910 GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(
1911 BKE_id_new_nomain(ID_GP, nullptr));
1912 return grease_pencil;
1913}
1914
1916{
1917 GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(
1918 BKE_id_copy_ex(nullptr, &grease_pencil_src->id, nullptr, LIB_ID_COPY_LOCALIZE));
1919 grease_pencil->runtime->eval_frame = grease_pencil_src->runtime->eval_frame;
1920 return grease_pencil;
1921}
1922
1933
1936{
1937 using namespace blender::bke::greasepencil;
1938 dst.as_node().flag = src.as_node().flag;
1940
1941 dst.blend_mode = src.blend_mode;
1942 dst.opacity = src.opacity;
1943
1944 LISTBASE_FOREACH (GreasePencilLayerMask *, src_mask, &src.masks) {
1945 LayerMask *new_mask = MEM_new<LayerMask>(__func__, *reinterpret_cast<LayerMask *>(src_mask));
1946 BLI_addtail(&dst.masks, reinterpret_cast<GreasePencilLayerMask *>(new_mask));
1947 }
1949
1950 dst.parent = src.parent;
1952 copy_m4_m4(dst.parentinv, src.parentinv);
1953
1955 copy_v3_v3(dst.rotation, src.rotation);
1956 copy_v3_v3(dst.scale, src.scale);
1957
1959}
1960
1969
1971 GreasePencil *grease_pencil_dst)
1972{
1973 using namespace blender;
1976
1977 /* Drawings. */
1978 free_drawing_array(*grease_pencil_dst);
1979 grease_pencil_dst->resize_drawings(grease_pencil_src->drawing_array_num);
1980 for (const int i : IndexRange(grease_pencil_dst->drawing_array_num)) {
1981 switch (grease_pencil_src->drawing_array[i]->type) {
1982 case GP_DRAWING: {
1983 const Drawing &src_drawing =
1984 reinterpret_cast<GreasePencilDrawing *>(grease_pencil_src->drawing_array[i])->wrap();
1985 grease_pencil_dst->drawing_array[i] = &MEM_new<Drawing>(__func__, src_drawing)->base;
1986 break;
1987 }
1989 const DrawingReference &src_drawing_ref = reinterpret_cast<GreasePencilDrawingReference *>(
1990 grease_pencil_src->drawing_array[i])
1991 ->wrap();
1992 grease_pencil_dst->drawing_array[i] =
1993 &MEM_new<DrawingReference>(__func__, src_drawing_ref)->base;
1994 break;
1995 }
1996 }
1997
1998 /* Layers. */
1999 CustomData_free(&grease_pencil_dst->layers_data, grease_pencil_src->layers().size());
2000 if (grease_pencil_dst->root_group_ptr) {
2001 MEM_delete(&grease_pencil_dst->root_group());
2002 }
2003
2004 grease_pencil_dst->root_group_ptr = MEM_new<bke::greasepencil::LayerGroup>(
2005 __func__, grease_pencil_src->root_group_ptr->wrap());
2006 BLI_assert(grease_pencil_src->layers().size() == grease_pencil_dst->layers().size());
2007
2008 /* Reset the active node. */
2009 grease_pencil_dst->active_node = nullptr;
2010
2011 CustomData_init_from(&grease_pencil_src->layers_data,
2012 &grease_pencil_dst->layers_data,
2013 eCustomDataMask(CD_MASK_ALL),
2014 grease_pencil_src->layers().size());
2015
2016 DEG_id_tag_update(&grease_pencil_dst->id, ID_RECALC_GEOMETRY);
2017
2018 BKE_id_free(nullptr, grease_pencil_src);
2019}
2020
2021void BKE_grease_pencil_vgroup_name_update(Object *ob, const char *old_name, const char *new_name)
2022{
2023 using namespace blender::bke::greasepencil;
2024 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob->data);
2025 for (GreasePencilDrawingBase *base : grease_pencil.drawings()) {
2026 Drawing &drawing = reinterpret_cast<GreasePencilDrawing *>(base)->wrap();
2027 CurvesGeometry &curves = drawing.strokes_for_write();
2028 LISTBASE_FOREACH (bDeformGroup *, vgroup, &curves.vertex_group_names) {
2029 if (strcmp(vgroup->name, old_name) == 0) {
2030 STRNCPY(vgroup->name, new_name);
2031 }
2032 }
2033 }
2034}
2035
2037 Scene *scene,
2038 Object *object,
2039 blender::bke::GeometrySet &geometry_set)
2040{
2041 /* Modifier evaluation modes. */
2042 const bool use_render = DEG_get_mode(depsgraph) == DAG_EVAL_RENDER;
2043 ModifierMode required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
2044 if (BKE_object_is_in_editmode(object)) {
2045 required_mode |= eModifierMode_Editmode;
2046 }
2047 ModifierApplyFlag apply_flag = use_render ? MOD_APPLY_RENDER : MOD_APPLY_USECACHE;
2048 const ModifierEvalContext mectx = {depsgraph, object, apply_flag};
2049
2051
2052 /* Get effective list of modifiers to execute. Some effects like shape keys
2053 * are added as virtual modifiers before the user created modifiers. */
2054 VirtualModifierData virtualModifierData;
2055 ModifierData *md = BKE_modifiers_get_virtual_modifierlist(object, &virtualModifierData);
2056
2057 /* Evaluate time modifiers.
2058 * The time offset modifier can change what drawings are shown on the current frame. But it
2059 * doesn't affect the drawings data. Modifiers that modify the drawings data are only evaluated
2060 * for the current frame, so we run the time offset modifiers before all the other ones. */
2061 ModifierData *tmd = md;
2062 for (; tmd; tmd = tmd->next) {
2064
2065 if (!BKE_modifier_is_enabled(scene, tmd, required_mode) ||
2067 {
2068 continue;
2069 }
2070
2071 blender::bke::ScopedModifierTimer modifier_timer{*md};
2072
2073 if (mti->modify_geometry_set != nullptr) {
2074 mti->modify_geometry_set(tmd, &mectx, &geometry_set);
2075 }
2076 }
2077
2078 /* Evaluate drawing modifiers. */
2079 for (; md; md = md->next) {
2081
2082 if (!BKE_modifier_is_enabled(scene, md, required_mode) ||
2084 {
2085 continue;
2086 }
2087
2088 blender::bke::ScopedModifierTimer modifier_timer{*md};
2089
2090 if (mti->modify_geometry_set != nullptr) {
2091 mti->modify_geometry_set(md, &mectx, &geometry_set);
2092 }
2093 }
2094}
2095
2097{
2098 using namespace blender;
2099 using namespace bke::greasepencil;
2100
2101 const bke::AttributeAccessor layer_attributes = grease_pencil.attributes();
2102
2103 struct LayerDrawingInfo {
2104 Drawing *drawing;
2105 const int layer_index;
2106 };
2107
2108 Set<Drawing *> all_drawings;
2109 Vector<LayerDrawingInfo> drawing_infos;
2110 for (const int layer_i : grease_pencil.layers().index_range()) {
2111 const Layer &layer = grease_pencil.layer(layer_i);
2112 /* Set of owned drawings, ignore drawing references to other data blocks. */
2113 if (Drawing *drawing = grease_pencil.get_eval_drawing(layer)) {
2114 if (all_drawings.add(drawing)) {
2115 drawing_infos.append({drawing, layer_i});
2116 }
2117 }
2118 }
2119
2120 if (layer_attributes.contains("radius_offset")) {
2121 const VArray<float> radius_offsets = *layer_attributes.lookup_or_default<float>(
2122 "radius_offset", bke::AttrDomain::Layer, 0.0f);
2123 threading::parallel_for_each(drawing_infos, [&](LayerDrawingInfo &info) {
2124 if (radius_offsets[info.layer_index] == 0.0f) {
2125 return;
2126 }
2127 MutableSpan<float> radii = info.drawing->radii_for_write();
2128 threading::parallel_for(radii.index_range(), 4096, [&](const IndexRange range) {
2129 for (const int i : range) {
2130 radii[i] += radius_offsets[info.layer_index];
2131 }
2132 });
2133 });
2134 }
2135
2136 if (layer_attributes.contains("tint_color")) {
2137 auto mix_tint = [](const float4 base, const float4 tint) -> float4 {
2138 return base * (1.0 - tint.w) + tint * tint.w;
2139 };
2140 const VArray<ColorGeometry4f> tint_colors =
2141 *layer_attributes.lookup_or_default<ColorGeometry4f>(
2142 "tint_color", bke::AttrDomain::Layer, ColorGeometry4f(0.0f, 0.0f, 0.0f, 0.0f));
2143 threading::parallel_for_each(drawing_infos, [&](LayerDrawingInfo &info) {
2144 if (tint_colors[info.layer_index].a == 0.0f) {
2145 return;
2146 }
2147 MutableSpan<ColorGeometry4f> vertex_colors = info.drawing->vertex_colors_for_write();
2148 threading::parallel_for(vertex_colors.index_range(), 4096, [&](const IndexRange range) {
2149 for (const int i : range) {
2150 vertex_colors[i] = ColorGeometry4f(
2151 mix_tint(float4(vertex_colors[i]), float4(tint_colors[info.layer_index])));
2152 }
2153 });
2154 MutableSpan<ColorGeometry4f> fill_colors = info.drawing->fill_colors_for_write();
2155 threading::parallel_for(fill_colors.index_range(), 4096, [&](const IndexRange range) {
2156 for (const int i : range) {
2157 fill_colors[i] = ColorGeometry4f(
2158 mix_tint(float4(fill_colors[i]), float4(tint_colors[info.layer_index])));
2159 }
2160 });
2161 });
2162 }
2163}
2164
2165void BKE_grease_pencil_data_update(Depsgraph *depsgraph, Scene *scene, Object *object)
2166{
2167 using namespace blender;
2168 using namespace blender::bke;
2169 /* Free any evaluated data and restore original data. */
2171
2172 /* Evaluate modifiers. */
2173 GreasePencil *grease_pencil = static_cast<GreasePencil *>(object->data);
2174 /* Store the frame that this grease pencil is evaluated on. */
2175 grease_pencil->runtime->eval_frame = int(DEG_get_ctime(depsgraph));
2176 GeometrySet geometry_set = GeometrySet::from_grease_pencil(grease_pencil,
2177 GeometryOwnershipType::ReadOnly);
2178 /* The layer adjustments for tinting and radii offsets are applied before modifier evaluation.
2179 * This ensures that the evaluated geometry contains the modifications. In the future, it would
2180 * be better to move these into modifiers. For now, these are hardcoded. */
2181 const bke::AttributeAccessor layer_attributes = grease_pencil->attributes();
2182 if (layer_attributes.contains("tint_color") || layer_attributes.contains("radius_offset")) {
2184 }
2185 /* Only add the edit hint component in edit mode for now so users can properly select deformed
2186 * drawings. */
2187 if (object->mode == OB_MODE_EDIT) {
2188 GeometryComponentEditData &edit_component =
2190 edit_component.grease_pencil_edit_hints_ = std::make_unique<GreasePencilEditHints>(
2191 *static_cast<const GreasePencil *>(DEG_get_original_object(object)->data));
2192 }
2193 grease_pencil_evaluate_modifiers(depsgraph, scene, object, geometry_set);
2194
2195 if (geometry_set.has_grease_pencil()) {
2196 /* Output geometry set may be different from the input,
2197 * set the frame again to ensure a correct value. */
2198 geometry_set.get_grease_pencil()->runtime->eval_frame = int(DEG_get_ctime(depsgraph));
2199 }
2200 else {
2201 GreasePencil *empty_grease_pencil = BKE_grease_pencil_new_nomain();
2202 empty_grease_pencil->runtime->eval_frame = int(DEG_get_ctime(depsgraph));
2203 geometry_set.replace_grease_pencil(empty_grease_pencil);
2204 }
2205
2206 /* For now the evaluated data is not const. We could use #get_grease_pencil_for_write, but that
2207 * would result in a copy when it's shared. So for now, we use a const_cast here. */
2208 GreasePencil *grease_pencil_eval = const_cast<GreasePencil *>(geometry_set.get_grease_pencil());
2209
2210 /* Assign evaluated object. */
2211 BKE_object_eval_assign_data(object, &grease_pencil_eval->id, false);
2212 object->runtime->geometry_set_eval = new GeometrySet(std::move(geometry_set));
2213}
2214
2216 GreasePencil *grease_pencil_dst)
2217{
2218 using namespace blender;
2219 grease_pencil_dst->drawing_array_num = grease_pencil_src->drawing_array_num;
2220 if (grease_pencil_dst->drawing_array_num > 0) {
2221 grease_pencil_dst->drawing_array = MEM_cnew_array<GreasePencilDrawingBase *>(
2222 grease_pencil_src->drawing_array_num, __func__);
2223 bke::greasepencil::copy_drawing_array(grease_pencil_src->drawings(),
2224 grease_pencil_dst->drawings());
2225 }
2226}
2227
2230/* ------------------------------------------------------------------- */
2236{
2237 using namespace blender;
2238
2239 int total_points = 0;
2240
2241 for (const int layer_i : grease_pencil.layers().index_range()) {
2242 const bke::greasepencil::Layer &layer = grease_pencil.layer(layer_i);
2243 const Map<bke::greasepencil::FramesMapKeyT, GreasePencilFrame> frames = layer.frames();
2244 frames.foreach_item(
2245 [&](const bke::greasepencil::FramesMapKeyT /*key*/, const GreasePencilFrame frame) {
2246 const GreasePencilDrawingBase *base = grease_pencil.drawing(frame.drawing_index);
2247 if (base->type != GP_DRAWING) {
2248 return;
2249 }
2250 const bke::greasepencil::Drawing &drawing =
2251 reinterpret_cast<const GreasePencilDrawing *>(base)->wrap();
2252 const bke::CurvesGeometry &curves = drawing.strokes();
2253 total_points += curves.points_num();
2254 });
2255 }
2256
2257 return total_points;
2258}
2259
2262{
2263 using namespace blender;
2264
2265 for (const int layer_i : grease_pencil.layers().index_range()) {
2266 const bke::greasepencil::Layer &layer = grease_pencil.layer(layer_i);
2267 const float4x4 layer_to_object = layer.local_transform();
2268 const Map<bke::greasepencil::FramesMapKeyT, GreasePencilFrame> frames = layer.frames();
2269 frames.foreach_item(
2270 [&](const bke::greasepencil::FramesMapKeyT /*key*/, const GreasePencilFrame frame) {
2271 const GreasePencilDrawingBase *base = grease_pencil.drawing(frame.drawing_index);
2272 if (base->type != GP_DRAWING) {
2273 return;
2274 }
2275 const bke::greasepencil::Drawing &drawing =
2276 reinterpret_cast<const GreasePencilDrawing *>(base)->wrap();
2277 const bke::CurvesGeometry &curves = drawing.strokes();
2278 const Span<float3> positions = curves.positions();
2279 const VArray<float> radii = drawing.radii();
2280
2281 for (const int i : curves.points_range()) {
2282 copy_v3_v3(elem_data->co, math::transform_point(layer_to_object, positions[i]));
2283 elem_data->radius = radii[i];
2284 elem_data++;
2285 }
2286 });
2287 }
2288}
2289
2292{
2293 using namespace blender;
2294
2295 for (const int layer_i : grease_pencil.layers().index_range()) {
2296 bke::greasepencil::Layer &layer = grease_pencil.layer(layer_i);
2297 const float4x4 layer_to_object = layer.local_transform();
2298 const float4x4 object_to_layer = math::invert(layer_to_object);
2299 const Map<bke::greasepencil::FramesMapKeyT, GreasePencilFrame> frames = layer.frames();
2300 frames.foreach_item([&](bke::greasepencil::FramesMapKeyT /*key*/, GreasePencilFrame frame) {
2301 GreasePencilDrawingBase *base = grease_pencil.drawing(frame.drawing_index);
2302 if (base->type != GP_DRAWING) {
2303 return;
2304 }
2305 bke::greasepencil::Drawing &drawing = reinterpret_cast<GreasePencilDrawing *>(base)->wrap();
2306 bke::CurvesGeometry &curves = drawing.strokes_for_write();
2307
2308 MutableSpan<float3> positions = curves.positions_for_write();
2309 MutableSpan<float> radii = drawing.radii_for_write();
2310
2311 for (const int i : curves.points_range()) {
2312 positions[i] = math::transform_point(object_to_layer, float3(elem_data->co));
2313 radii[i] = elem_data->radius;
2314 elem_data++;
2315 }
2316 });
2317 }
2318}
2319
2322 const blender::float4x4 &mat)
2323{
2324 using namespace blender;
2325
2326 const float scalef = mat4_to_scale(mat.ptr());
2327
2328 for (const int layer_i : grease_pencil.layers().index_range()) {
2329 bke::greasepencil::Layer &layer = grease_pencil.layer(layer_i);
2330 const float4x4 layer_to_object = layer.local_transform();
2331 const float4x4 object_to_layer = math::invert(layer_to_object);
2332 const Map<bke::greasepencil::FramesMapKeyT, GreasePencilFrame> frames = layer.frames();
2333 frames.foreach_item([&](bke::greasepencil::FramesMapKeyT /*key*/, GreasePencilFrame frame) {
2334 GreasePencilDrawingBase *base = grease_pencil.drawing(frame.drawing_index);
2335 if (base->type != GP_DRAWING) {
2336 return;
2337 }
2338 bke::greasepencil::Drawing &drawing = reinterpret_cast<GreasePencilDrawing *>(base)->wrap();
2339 bke::CurvesGeometry &curves = drawing.strokes_for_write();
2340
2341 MutableSpan<float3> positions = curves.positions_for_write();
2342 MutableSpan<float> radii = drawing.radii_for_write();
2343
2344 for (const int i : curves.points_range()) {
2345 positions[i] = math::transform_point(object_to_layer * mat, float3(elem_data->co));
2346 radii[i] = elem_data->radius * scalef;
2347 elem_data++;
2348 }
2349 });
2350 }
2351}
2352
2355/* ------------------------------------------------------------------- */
2360{
2361 short *totcol = BKE_object_material_len_p(ob);
2362 Material *read_ma = nullptr;
2363 for (short i = 0; i < *totcol; i++) {
2364 read_ma = BKE_object_material_get(ob, i + 1);
2365 if (STREQ(name, read_ma->id.name + 2)) {
2366 return i;
2367 }
2368 }
2369
2370 return -1;
2371}
2372
2374 Object *ob,
2375 const char *name,
2376 int *r_index)
2377{
2378 Material *ma = BKE_gpencil_material_add(bmain, name);
2379 id_us_min(&ma->id); /* no users yet */
2380
2383
2384 if (r_index) {
2385 *r_index = ob->actcol - 1;
2386 }
2387 return ma;
2388}
2389
2391{
2392 if ((brush) && (brush->gpencil_settings) &&
2394 {
2396 return ma;
2397 }
2398
2399 return BKE_object_material_get(ob, ob->actcol);
2400}
2401
2403 Object *ob,
2404 const char *name,
2405 int *r_index)
2406{
2408 if (index != -1) {
2409 *r_index = index;
2410 return BKE_object_material_get(ob, index + 1);
2411 }
2412 return BKE_grease_pencil_object_material_new(bmain, ob, name, r_index);
2413}
2414
2416{
2417 if (brush == nullptr) {
2418 return nullptr;
2419 }
2420 if (brush->gpencil_settings == nullptr) {
2421 return nullptr;
2422 }
2423 return brush->gpencil_settings->material;
2424}
2425
2427 Object *ob,
2428 Brush *brush)
2429{
2432
2433 /* check if the material is already on object material slots and add it if missing */
2434 if (ma && BKE_object_material_index_get(ob, ma) < 0) {
2437 }
2438
2439 return ma;
2440 }
2441
2442 /* Use the active material instead. */
2443 return BKE_object_material_get(ob, ob->actcol);
2444}
2445
2447 Object *ob,
2448 Brush *brush)
2449{
2450 if (brush == nullptr) {
2452 }
2454 return ma;
2455 }
2457 /* It is easier to just unpin a null material, instead of setting a new one. */
2458 brush->gpencil_settings->flag &= ~GP_BRUSH_MATERIAL_PINNED;
2459 }
2461}
2462
2470
2479
2480void BKE_grease_pencil_material_remap(GreasePencil *grease_pencil, const uint *remap, int totcol)
2481{
2482 using namespace blender::bke;
2483
2484 for (GreasePencilDrawingBase *base : grease_pencil->drawings()) {
2485 if (base->type != GP_DRAWING) {
2486 continue;
2487 }
2488 greasepencil::Drawing &drawing = reinterpret_cast<GreasePencilDrawing *>(base)->wrap();
2490 SpanAttributeWriter<int> material_indices = attributes.lookup_for_write_span<int>(
2491 "material_index");
2492 if (!material_indices) {
2493 continue;
2494 }
2495 BLI_assert(material_indices.domain == AttrDomain::Curve);
2496 for (const int i : material_indices.span.index_range()) {
2497 BLI_assert(blender::IndexRange(totcol).contains(remap[material_indices.span[i]]));
2498 UNUSED_VARS_NDEBUG(totcol);
2499 material_indices.span[i] = remap[material_indices.span[i]];
2500 }
2501 material_indices.finish();
2502 }
2503}
2504
2505void BKE_grease_pencil_material_index_remove(GreasePencil *grease_pencil, const int index)
2506{
2507 using namespace blender;
2508 using namespace blender::bke;
2509
2510 for (GreasePencilDrawingBase *base : grease_pencil->drawings()) {
2511 if (base->type != GP_DRAWING) {
2512 continue;
2513 }
2514 greasepencil::Drawing &drawing = reinterpret_cast<GreasePencilDrawing *>(base)->wrap();
2516 SpanAttributeWriter<int> material_indices = attributes.lookup_for_write_span<int>(
2517 "material_index");
2518 if (!material_indices) {
2519 continue;
2520 }
2521 BLI_assert(material_indices.domain == AttrDomain::Curve);
2522 for (const int i : material_indices.span.index_range()) {
2523 if (material_indices.span[i] > 0 && material_indices.span[i] >= index) {
2524 material_indices.span[i]--;
2525 }
2526 }
2527 material_indices.finish();
2528 }
2529}
2530
2532{
2533 using namespace blender;
2534 using namespace blender::bke;
2535
2536 for (GreasePencilDrawingBase *base : grease_pencil->drawings()) {
2537 if (base->type != GP_DRAWING) {
2538 continue;
2539 }
2540 greasepencil::Drawing &drawing = reinterpret_cast<GreasePencilDrawing *>(base)->wrap();
2541 AttributeAccessor attributes = drawing.strokes().attributes();
2542 const VArraySpan<int> material_indices = *attributes.lookup_or_default<int>(
2543 "material_index", AttrDomain::Curve, 0);
2544
2545 if (material_indices.contains(index)) {
2546 return true;
2547 }
2548 }
2549 return false;
2550}
2551
2554/* ------------------------------------------------------------------- */
2559 const GreasePencil *grease_pencil)
2560{
2561 for (const GreasePencilDrawingBase *base : grease_pencil->drawings()) {
2562 if (base->type == GP_DRAWING_REFERENCE) {
2563 const auto *reference = reinterpret_cast<const GreasePencilDrawingReference *>(base);
2564 if (id_reference == reference->id_reference) {
2565 return true;
2566 }
2567
2568 if (grease_pencil_references_cyclic_check_internal(id_reference, reference->id_reference)) {
2569 return true;
2570 }
2571 }
2572 }
2573 return false;
2574}
2575
2577 const GreasePencil *grease_pencil)
2578{
2579 return grease_pencil_references_cyclic_check_internal(id_reference, grease_pencil);
2580}
2581
2584/* ------------------------------------------------------------------- */
2589 int mode) = nullptr;
2590void (*BKE_grease_pencil_batch_cache_free_cb)(GreasePencil *grease_pencil) = nullptr;
2591
2593{
2594 if (grease_pencil->runtime && grease_pencil->runtime->batch_cache) {
2595 BKE_grease_pencil_batch_cache_dirty_tag_cb(grease_pencil, mode);
2596 }
2597}
2598
2600{
2601 if (grease_pencil->runtime && grease_pencil->runtime->batch_cache) {
2603 }
2604}
2605
2608/* ------------------------------------------------------------------- */
2612template<typename T> static void grow_array(T **array, int *num, const int add_num)
2613{
2614 BLI_assert(add_num > 0);
2615 const int new_array_num = *num + add_num;
2616 T *new_array = MEM_cnew_array<T>(new_array_num, __func__);
2617
2618 blender::uninitialized_relocate_n(*array, *num, new_array);
2619 if (*array != nullptr) {
2620 MEM_freeN(*array);
2621 }
2622
2623 *array = new_array;
2624 *num = new_array_num;
2625}
2626template<typename T> static void shrink_array(T **array, int *num, const int shrink_num)
2627{
2628 BLI_assert(shrink_num > 0);
2629 const int new_array_num = *num - shrink_num;
2630 if (new_array_num == 0) {
2631 MEM_freeN(*array);
2632 *array = nullptr;
2633 *num = 0;
2634 return;
2635 }
2636
2637 T *new_array = MEM_cnew_array<T>(new_array_num, __func__);
2638
2639 blender::uninitialized_move_n(*array, new_array_num, new_array);
2640 MEM_freeN(*array);
2641
2642 *array = new_array;
2643 *num = new_array_num;
2644}
2645
2646blender::Span<const GreasePencilDrawingBase *> GreasePencil::drawings() const
2647{
2648 return blender::Span<GreasePencilDrawingBase *>{this->drawing_array, this->drawing_array_num};
2649}
2650
2652{
2653 return blender::MutableSpan<GreasePencilDrawingBase *>{this->drawing_array,
2654 this->drawing_array_num};
2655}
2656
2657static void delete_drawing(GreasePencilDrawingBase *drawing_base)
2658{
2659 switch (GreasePencilDrawingType(drawing_base->type)) {
2660 case GP_DRAWING: {
2661 GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_base);
2662 MEM_delete(&drawing->wrap());
2663 break;
2664 }
2665 case GP_DRAWING_REFERENCE: {
2666 GreasePencilDrawingReference *drawing_reference =
2667 reinterpret_cast<GreasePencilDrawingReference *>(drawing_base);
2668 MEM_delete(&drawing_reference->wrap());
2669 break;
2670 }
2671 }
2672}
2673
2674void GreasePencil::resize_drawings(const int new_num)
2675{
2676 using namespace blender;
2677 BLI_assert(new_num >= 0);
2678
2679 const int prev_num = int(this->drawings().size());
2680 if (new_num == prev_num) {
2681 return;
2682 }
2683 if (new_num > prev_num) {
2684 const int add_num = new_num - prev_num;
2685 grow_array<GreasePencilDrawingBase *>(&this->drawing_array, &this->drawing_array_num, add_num);
2686 }
2687 else { /* if (new_num < prev_num) */
2688 const int shrink_num = prev_num - new_num;
2689 MutableSpan<GreasePencilDrawingBase *> old_drawings = this->drawings().drop_front(new_num);
2690 for (const int64_t i : old_drawings.index_range()) {
2691 if (GreasePencilDrawingBase *drawing_base = old_drawings[i]) {
2692 delete_drawing(drawing_base);
2693 }
2694 }
2696 &this->drawing_array, &this->drawing_array_num, shrink_num);
2697 }
2698}
2699
2700void GreasePencil::add_empty_drawings(const int add_num)
2701{
2702 using namespace blender;
2703 BLI_assert(add_num > 0);
2704 const int prev_num = this->drawings().size();
2705 grow_array<GreasePencilDrawingBase *>(&this->drawing_array, &this->drawing_array_num, add_num);
2706 MutableSpan<GreasePencilDrawingBase *> new_drawings = this->drawings().drop_front(prev_num);
2707 for (const int i : new_drawings.index_range()) {
2708 new_drawings[i] = reinterpret_cast<GreasePencilDrawingBase *>(
2709 MEM_new<blender::bke::greasepencil::Drawing>(__func__));
2710 }
2711}
2712
2713void GreasePencil::add_duplicate_drawings(const int duplicate_num,
2715{
2716 using namespace blender;
2717 BLI_assert(duplicate_num > 0);
2718 const int prev_num = this->drawings().size();
2720 &this->drawing_array, &this->drawing_array_num, duplicate_num);
2721 MutableSpan<GreasePencilDrawingBase *> new_drawings = this->drawings().drop_front(prev_num);
2722 for (const int i : new_drawings.index_range()) {
2723 new_drawings[i] = reinterpret_cast<GreasePencilDrawingBase *>(
2724 MEM_new<bke::greasepencil::Drawing>(__func__, drawing));
2725 }
2726}
2727
2728blender::bke::greasepencil::Drawing *GreasePencil::insert_frame(
2730 const int frame_number,
2731 const int duration,
2732 const eBezTriple_KeyframeType keytype)
2733{
2734 using namespace blender;
2735 GreasePencilFrame *frame = layer.add_frame(frame_number, duration);
2736 if (frame == nullptr) {
2737 return nullptr;
2738 }
2739 this->add_empty_drawings(1);
2740 frame->drawing_index = this->drawings().index_range().last();
2741 frame->type = int8_t(keytype);
2742
2743 GreasePencilDrawingBase *drawing_base = this->drawings().last();
2744 BLI_assert(drawing_base->type == GP_DRAWING);
2745 GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_base);
2746 return &drawing->wrap();
2747}
2748
2749void GreasePencil::insert_frames(Span<blender::bke::greasepencil::Layer *> layers,
2750 const int frame_number,
2751 const int duration,
2752 const eBezTriple_KeyframeType keytype)
2753{
2754 using namespace blender;
2755 if (layers.is_empty()) {
2756 return;
2757 }
2758 Vector<GreasePencilFrame *> frames;
2759 frames.reserve(layers.size());
2760 for (bke::greasepencil::Layer *layer : layers) {
2761 BLI_assert(layer != nullptr);
2762 GreasePencilFrame *frame = layer->add_frame(frame_number, duration);
2763 if (frame != nullptr) {
2764 frames.append(frame);
2765 }
2766 }
2767
2768 if (frames.is_empty()) {
2769 return;
2770 }
2771
2772 this->add_empty_drawings(frames.size());
2773 const IndexRange new_drawings = this->drawings().index_range().take_back(frames.size());
2774 for (const int frame_i : frames.index_range()) {
2775 GreasePencilFrame *frame = frames[frame_i];
2776 frame->drawing_index = new_drawings[frame_i];
2777 frame->type = int8_t(keytype);
2778 }
2779}
2780
2781bool GreasePencil::insert_duplicate_frame(blender::bke::greasepencil::Layer &layer,
2782 const int src_frame_number,
2783 const int dst_frame_number,
2784 const bool do_instance)
2785{
2786 using namespace blender::bke::greasepencil;
2787
2788 if (!layer.frames().contains(src_frame_number)) {
2789 return false;
2790 }
2791 const GreasePencilFrame src_frame = layer.frames().lookup(src_frame_number);
2792
2793 /* Create the new frame structure, with the same duration.
2794 * If we want to make an instance of the source frame, the drawing index gets copied from the
2795 * source frame. Otherwise, we set the drawing index to the size of the drawings array, since we
2796 * are going to add a new drawing copied from the source drawing. */
2797 const int duration = layer.get_frame_duration_at(src_frame_number);
2798 GreasePencilFrame *dst_frame = layer.add_frame(dst_frame_number, duration);
2799 if (dst_frame == nullptr) {
2800 return false;
2801 }
2802 dst_frame->drawing_index = do_instance ? src_frame.drawing_index : int(this->drawings().size());
2803 dst_frame->type = src_frame.type;
2804
2805 const GreasePencilDrawingBase *src_drawing_base = this->drawing(src_frame.drawing_index);
2806 switch (src_drawing_base->type) {
2807 case GP_DRAWING: {
2808 const Drawing &src_drawing =
2809 reinterpret_cast<const GreasePencilDrawing *>(src_drawing_base)->wrap();
2810 if (do_instance) {
2811 /* Adds the duplicate frame as a new instance of the same drawing. We thus increase the
2812 * user count of the corresponding drawing. */
2813 src_drawing.add_user();
2814 }
2815 else {
2816 /* Create a copy of the drawing, and add it at the end of the drawings array.
2817 * Note that the frame already points to this new drawing, as the drawing index was set to
2818 * `int(this->drawings().size())`. */
2819 this->add_duplicate_drawings(1, src_drawing);
2820 }
2821 break;
2822 }
2824 /* TODO: Duplicate drawing references is not yet implemented.
2825 * For now, just remove the frame that we inserted. */
2826 layer.remove_frame(dst_frame_number);
2827 return false;
2828 }
2829 return true;
2830}
2831
2832bool GreasePencil::remove_frames(blender::bke::greasepencil::Layer &layer,
2833 blender::Span<int> frame_numbers)
2834{
2835 using namespace blender::bke::greasepencil;
2836 bool removed_any_drawing_user = false;
2837 for (const int frame_number : frame_numbers) {
2838 if (!layer.frames().contains(frame_number)) {
2839 continue;
2840 }
2841 const GreasePencilFrame frame_to_remove = layer.frames().lookup(frame_number);
2842 const int64_t drawing_index_to_remove = frame_to_remove.drawing_index;
2843 if (!layer.remove_frame(frame_number)) {
2844 /* If removing the frame was not successful, continue. */
2845 continue;
2846 }
2847 if (frame_to_remove.is_end()) {
2848 /* End frames don't reference a drawing, continue. */
2849 continue;
2850 }
2851 GreasePencilDrawingBase *drawing_base = this->drawing(drawing_index_to_remove);
2852 if (drawing_base->type != GP_DRAWING) {
2853 /* If the drawing is referenced from another object, we don't track it's users because we
2854 * cannot delete drawings from another object. */
2855 continue;
2856 }
2857 Drawing &drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_base)->wrap();
2858 drawing.remove_user();
2859 removed_any_drawing_user = true;
2860 }
2861 if (removed_any_drawing_user) {
2862 this->remove_drawings_with_no_users();
2863 return true;
2864 }
2865 return false;
2866}
2867
2868void GreasePencil::add_layers_with_empty_drawings_for_eval(const int num)
2869{
2870 using namespace blender;
2871 using namespace blender::bke::greasepencil;
2872 const int old_drawings_num = this->drawing_array_num;
2873 const int old_layers_num = this->layers().size();
2874 this->add_empty_drawings(num);
2875 this->add_layers_for_eval(num);
2876 threading::parallel_for(IndexRange(num), 256, [&](const IndexRange range) {
2877 for (const int i : range) {
2878 const int new_drawing_i = old_drawings_num + i;
2879 const int new_layer_i = old_layers_num + i;
2880 Drawing &drawing =
2881 reinterpret_cast<GreasePencilDrawing *>(this->drawing(new_drawing_i))->wrap();
2882 Layer &layer = this->layer(new_layer_i);
2883 GreasePencilFrame *frame = layer.add_frame(this->runtime->eval_frame);
2884 BLI_assert(frame);
2885 frame->drawing_index = new_drawing_i;
2886 drawing.add_user();
2887 }
2888 });
2889}
2890
2891void GreasePencil::remove_drawings_with_no_users()
2892{
2893 using namespace blender;
2894 using namespace blender::bke::greasepencil;
2895
2896 /* Compress the drawings array by finding unused drawings.
2897 * In every step two indices are found:
2898 * - The next unused drawing from the start
2899 * - The last used drawing from the end
2900 * These two drawings are then swapped. Rinse and repeat until both iterators meet somewhere in
2901 * the middle. At this point the drawings array is fully compressed.
2902 * Then the drawing indices in frame data are remapped. */
2903
2904 const MutableSpan<GreasePencilDrawingBase *> drawings = this->drawings();
2905 if (drawings.is_empty()) {
2906 return;
2907 }
2908
2909 auto is_drawing_used = [&](const int drawing_index) {
2910 GreasePencilDrawingBase *drawing_base = drawings[drawing_index];
2911 /* NOTE: GreasePencilDrawingReference does not have a user count currently, but should
2912 * eventually be counted like GreasePencilDrawing. */
2913 if (drawing_base->type != GP_DRAWING) {
2914 return false;
2915 }
2916 GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_base);
2917 return drawing->wrap().has_users();
2918 };
2919
2920 /* Index map to remap drawing indices in frame data.
2921 * Index -1 indicates that the drawing has not been moved. */
2922 constexpr const int unchanged_index = -1;
2923 Array<int> drawing_index_map(drawings.size(), unchanged_index);
2924
2925 int first_unused_drawing = -1;
2926 int last_used_drawing = drawings.size() - 1;
2927 /* Advance head and tail iterators to the next unused/used drawing respectively.
2928 * Returns true if an index pair was found that needs to be swapped. */
2929 auto find_next_swap_index = [&]() -> bool {
2930 do {
2931 ++first_unused_drawing;
2932 } while (first_unused_drawing <= last_used_drawing && is_drawing_used(first_unused_drawing));
2933 while (last_used_drawing >= 0 && !is_drawing_used(last_used_drawing)) {
2934 --last_used_drawing;
2935 }
2936
2937 return first_unused_drawing < last_used_drawing;
2938 };
2939
2940 while (find_next_swap_index()) {
2941 /* Found two valid iterators, now swap drawings. */
2942 std::swap(drawings[first_unused_drawing], drawings[last_used_drawing]);
2943 drawing_index_map[last_used_drawing] = first_unused_drawing;
2944 }
2945
2946 /* `last_used_drawing` is expected to be exactly the item before the first unused drawing, once
2947 * the loop above is fully done and all unused drawings are supposed to be at the end of the
2948 * array. */
2949 BLI_assert(last_used_drawing == first_unused_drawing - 1);
2950#ifndef NDEBUG
2951 for (const int i : drawings.index_range()) {
2952 if (i < first_unused_drawing) {
2953 BLI_assert(is_drawing_used(i));
2954 }
2955 else {
2956 BLI_assert(!is_drawing_used(i));
2957 }
2958 }
2959#endif
2960
2961 /* Tail range of unused drawings that can be removed. */
2962 const IndexRange drawings_to_remove = (first_unused_drawing > 0) ?
2963 drawings.index_range().drop_front(
2964 first_unused_drawing) :
2965 drawings.index_range();
2966 if (drawings_to_remove.is_empty()) {
2967 return;
2968 }
2969
2970 /* Free the unused drawings. */
2971 for (const int i : drawings_to_remove) {
2972 GreasePencilDrawingBase *unused_drawing_base = drawings[i];
2973 switch (unused_drawing_base->type) {
2974 case GP_DRAWING: {
2975 auto *unused_drawing = reinterpret_cast<GreasePencilDrawing *>(unused_drawing_base);
2976 MEM_delete(&unused_drawing->wrap());
2977 break;
2978 }
2979 case GP_DRAWING_REFERENCE: {
2980 auto *unused_drawing_ref = reinterpret_cast<GreasePencilDrawingReference *>(
2981 unused_drawing_base);
2982 MEM_delete(&unused_drawing_ref->wrap());
2983 break;
2984 }
2985 }
2986 }
2988 &this->drawing_array, &this->drawing_array_num, drawings_to_remove.size());
2989
2990 /* Remap drawing indices in frame data. */
2991 for (Layer *layer : this->layers_for_write()) {
2992 for (auto [key, value] : layer->frames_for_write().items()) {
2993 const int new_drawing_index = drawing_index_map[value.drawing_index];
2994 if (new_drawing_index != unchanged_index) {
2995 value.drawing_index = new_drawing_index;
2996 layer->tag_frames_map_changed();
2997 }
2998 }
2999 }
3000}
3001
3002void GreasePencil::update_drawing_users_for_layer(const blender::bke::greasepencil::Layer &layer)
3003{
3004 using namespace blender;
3005 for (auto [key, value] : layer.frames().items()) {
3006 BLI_assert(this->drawings().index_range().contains(value.drawing_index));
3007 GreasePencilDrawingBase *drawing_base = this->drawing(value.drawing_index);
3008 if (drawing_base->type != GP_DRAWING) {
3009 continue;
3010 }
3012 reinterpret_cast<GreasePencilDrawing *>(drawing_base)->wrap();
3013 if (!drawing.has_users()) {
3014 drawing.add_user();
3015 }
3016 }
3017}
3018
3019void GreasePencil::move_frames(blender::bke::greasepencil::Layer &layer,
3020 const blender::Map<int, int> &frame_number_destinations)
3021{
3022 return this->move_duplicate_frames(
3023 layer, frame_number_destinations, blender::Map<int, GreasePencilFrame>());
3024}
3025
3026void GreasePencil::move_duplicate_frames(
3028 const blender::Map<int, int> &frame_number_destinations,
3029 const blender::Map<int, GreasePencilFrame> &duplicate_frames)
3030{
3031 using namespace blender;
3032 Map<int, GreasePencilFrame> layer_frames_copy = layer.frames();
3033
3034 /* Copy frames durations. */
3035 Map<int, int> src_layer_frames_durations;
3036 for (const auto [frame_number, frame] : layer.frames().items()) {
3037 src_layer_frames_durations.add(frame_number, layer.get_frame_duration_at(frame_number));
3038 }
3039
3040 /* Remove original frames for duplicates before inserting any frames.
3041 * This has to be done early to avoid removing frames that may be inserted
3042 * in place of the source frames. */
3043 for (const auto src_frame_number : frame_number_destinations.keys()) {
3044 if (!duplicate_frames.contains(src_frame_number)) {
3045 /* User count not decremented here, the same frame is inserted again later. */
3046 layer.remove_frame(src_frame_number);
3047 }
3048 }
3049
3050 auto get_source_frame = [&](const int frame_number) -> const GreasePencilFrame * {
3051 if (const GreasePencilFrame *ptr = duplicate_frames.lookup_ptr(frame_number)) {
3052 return ptr;
3053 }
3054 return layer_frames_copy.lookup_ptr(frame_number);
3055 };
3056
3057 for (const auto [src_frame_number, dst_frame_number] : frame_number_destinations.items()) {
3058 const GreasePencilFrame *src_frame = get_source_frame(src_frame_number);
3059 if (!src_frame) {
3060 continue;
3061 }
3062 const int duration = src_layer_frames_durations.lookup_default(src_frame_number, 0);
3063
3064 /* Add and overwrite the frame at the destination number. */
3065 if (layer.frames().contains(dst_frame_number)) {
3066 GreasePencilFrame frame_to_overwrite = layer.frames().lookup(dst_frame_number);
3067 GreasePencilDrawingBase *drawing_base = this->drawing(frame_to_overwrite.drawing_index);
3068 if (drawing_base->type == GP_DRAWING) {
3069 reinterpret_cast<GreasePencilDrawing *>(drawing_base)->wrap().remove_user();
3070 }
3071 layer.remove_frame(dst_frame_number);
3072 }
3073 GreasePencilFrame *frame = layer.add_frame(dst_frame_number, duration);
3074 *frame = *src_frame;
3075 }
3076
3077 /* Remove drawings if they no longer have users. */
3078 this->remove_drawings_with_no_users();
3079}
3080
3081const blender::bke::greasepencil::Drawing *GreasePencil::get_drawing_at(
3082 const blender::bke::greasepencil::Layer &layer, const int frame_number) const
3083{
3084 const int drawing_index = layer.drawing_index_at(frame_number);
3085 if (drawing_index == -1) {
3086 /* No drawing found. */
3087 return nullptr;
3088 }
3089 const GreasePencilDrawingBase *drawing_base = this->drawing(drawing_index);
3090 if (drawing_base->type != GP_DRAWING) {
3091 /* TODO: Get reference drawing. */
3092 return nullptr;
3093 }
3094 const GreasePencilDrawing *drawing = reinterpret_cast<const GreasePencilDrawing *>(drawing_base);
3095 return &drawing->wrap();
3096}
3097
3098blender::bke::greasepencil::Drawing *GreasePencil::get_drawing_at(
3099 const blender::bke::greasepencil::Layer &layer, const int frame_number)
3100{
3101 const int drawing_index = layer.drawing_index_at(frame_number);
3102 if (drawing_index == -1) {
3103 /* No drawing found. */
3104 return nullptr;
3105 }
3106 GreasePencilDrawingBase *drawing_base = this->drawing(drawing_index);
3107 if (drawing_base->type != GP_DRAWING) {
3108 /* TODO: Get reference drawing. */
3109 return nullptr;
3110 }
3111 GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_base);
3112 return &drawing->wrap();
3113}
3114
3115blender::bke::greasepencil::Drawing *GreasePencil::get_editable_drawing_at(
3116 const blender::bke::greasepencil::Layer &layer, const int frame_number)
3117{
3118 if (!layer.is_editable()) {
3119 return nullptr;
3120 }
3121
3122 const int drawing_index = layer.drawing_index_at(frame_number);
3123 if (drawing_index == -1) {
3124 /* No drawing found. */
3125 return nullptr;
3126 }
3127 GreasePencilDrawingBase *drawing_base = this->drawing(drawing_index);
3128 if (drawing_base->type != GP_DRAWING) {
3129 /* Drawing references are not editable. */
3130 return nullptr;
3131 }
3132 GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_base);
3133 return &drawing->wrap();
3134}
3135
3136const blender::bke::greasepencil::Drawing *GreasePencil::get_eval_drawing(
3137 const blender::bke::greasepencil::Layer &layer) const
3138{
3139 return this->get_drawing_at(layer, this->runtime->eval_frame);
3140}
3141
3142blender::bke::greasepencil::Drawing *GreasePencil::get_eval_drawing(
3144{
3145 return this->get_drawing_at(layer, this->runtime->eval_frame);
3146}
3147
3149 const blender::float4x4 &transform,
3151{
3152 BLI_assert(src.size() == dst.size());
3153
3155 for (const int i : range) {
3156 dst[i] = blender::math::transform_point(transform, src[i]);
3157 }
3158 });
3159}
3160
3161std::optional<blender::Bounds<blender::float3>> GreasePencil::bounds_min_max(const int frame) const
3162{
3163 using namespace blender;
3164 std::optional<Bounds<float3>> bounds;
3165 const Span<const bke::greasepencil::Layer *> layers = this->layers();
3166 for (const int layer_i : layers.index_range()) {
3167 const bke::greasepencil::Layer &layer = *layers[layer_i];
3168 const float4x4 layer_to_object = layer.local_transform();
3169 if (!layer.is_visible()) {
3170 continue;
3171 }
3172 if (const bke::greasepencil::Drawing *drawing = this->get_drawing_at(layer, frame)) {
3173 const bke::CurvesGeometry &curves = drawing->strokes();
3174
3175 Array<float3> world_pos(curves.evaluated_positions().size());
3176 transform_positions(curves.evaluated_positions(), layer_to_object, world_pos);
3177 bounds = bounds::merge(bounds, bounds::min_max(world_pos.as_span()));
3178 }
3179 }
3180 return bounds;
3181}
3182
3183std::optional<blender::Bounds<blender::float3>> GreasePencil::bounds_min_max_eval() const
3184{
3185 return this->bounds_min_max(this->runtime->eval_frame);
3186}
3187
3188void GreasePencil::count_memory(blender::MemoryCounter &memory) const
3189{
3190 using namespace blender::bke;
3191 for (const GreasePencilDrawingBase *base : this->drawings()) {
3192 if (base->type != GP_DRAWING) {
3193 continue;
3194 }
3195 const greasepencil::Drawing &drawing =
3196 reinterpret_cast<const GreasePencilDrawing *>(base)->wrap();
3197 drawing.strokes().count_memory(memory);
3198 }
3199}
3200
3202{
3203 BLI_assert(this->runtime != nullptr);
3204 return this->root_group().layers();
3205}
3206
3207blender::Span<blender::bke::greasepencil::Layer *> GreasePencil::layers_for_write()
3208{
3209 BLI_assert(this->runtime != nullptr);
3210 return this->root_group().layers_for_write();
3211}
3212
3214{
3215 BLI_assert(this->runtime != nullptr);
3216 return this->root_group().groups();
3217}
3218
3219blender::Span<blender::bke::greasepencil::LayerGroup *> GreasePencil::layer_groups_for_write()
3220{
3221 BLI_assert(this->runtime != nullptr);
3222 return this->root_group().groups_for_write();
3223}
3224
3226{
3227 BLI_assert(this->runtime != nullptr);
3228 return this->root_group().nodes();
3229}
3230
3231blender::Span<blender::bke::greasepencil::TreeNode *> GreasePencil::nodes_for_write()
3232{
3233 BLI_assert(this->runtime != nullptr);
3234 return this->root_group().nodes_for_write();
3235}
3236
3237std::optional<int> GreasePencil::get_layer_index(
3238 const blender::bke::greasepencil::Layer &layer) const
3239{
3240 const int index = int(this->layers().first_index_try(&layer));
3241 if (index == -1) {
3242 return {};
3243 }
3244 return index;
3245}
3246
3247const blender::bke::greasepencil::Layer *GreasePencil::get_active_layer() const
3248{
3249 if (this->active_node == nullptr) {
3250 return nullptr;
3251 }
3252 const blender::bke::greasepencil::TreeNode &active_node = *this->get_active_node();
3253 if (!active_node.is_layer()) {
3254 return nullptr;
3255 }
3256 return &active_node.as_layer();
3257}
3258
3259blender::bke::greasepencil::Layer *GreasePencil::get_active_layer()
3260{
3261 if (this->active_node == nullptr) {
3262 return nullptr;
3263 }
3264 blender::bke::greasepencil::TreeNode &active_node = *this->get_active_node();
3265 if (!active_node.is_layer()) {
3266 return nullptr;
3267 }
3268 return &active_node.as_layer();
3269}
3270
3271void GreasePencil::set_active_layer(blender::bke::greasepencil::Layer *layer)
3272{
3273 this->active_node = reinterpret_cast<GreasePencilLayerTreeNode *>(&layer->as_node());
3274
3275 if (this->flag & GREASE_PENCIL_AUTOLOCK_LAYERS) {
3276 this->autolock_inactive_layers();
3277 }
3278}
3279
3280bool GreasePencil::is_layer_active(const blender::bke::greasepencil::Layer *layer) const
3281{
3282 if (layer == nullptr) {
3283 return false;
3284 }
3285 return this->get_active_layer() == layer;
3286}
3287
3288void GreasePencil::autolock_inactive_layers()
3289{
3290 using namespace blender::bke::greasepencil;
3291
3292 for (Layer *layer : this->layers_for_write()) {
3293 if (this->is_layer_active(layer)) {
3294 layer->set_locked(false);
3295 continue;
3296 }
3297 layer->set_locked(true);
3298 }
3299}
3300
3301const blender::bke::greasepencil::LayerGroup *GreasePencil::get_active_group() const
3302{
3303 if (this->active_node == nullptr) {
3304 return nullptr;
3305 }
3306 const blender::bke::greasepencil::TreeNode &active_node = *this->get_active_node();
3307 if (!active_node.is_group()) {
3308 return nullptr;
3309 }
3310 return &active_node.as_group();
3311}
3312
3313blender::bke::greasepencil::LayerGroup *GreasePencil::get_active_group()
3314{
3315 if (this->active_node == nullptr) {
3316 return nullptr;
3317 }
3318 blender::bke::greasepencil::TreeNode &active_node = *this->get_active_node();
3319 if (!active_node.is_group()) {
3320 return nullptr;
3321 }
3322 return &active_node.as_group();
3323}
3324
3325const blender::bke::greasepencil::TreeNode *GreasePencil::get_active_node() const
3326{
3327 if (this->active_node == nullptr) {
3328 return nullptr;
3329 }
3330 return &this->active_node->wrap();
3331}
3332
3333blender::bke::greasepencil::TreeNode *GreasePencil::get_active_node()
3334{
3335 if (this->active_node == nullptr) {
3336 return nullptr;
3337 }
3338 return &this->active_node->wrap();
3339}
3340
3341void GreasePencil::set_active_node(blender::bke::greasepencil::TreeNode *node)
3342{
3343 this->active_node = reinterpret_cast<GreasePencilLayerTreeNode *>(node);
3344}
3345
3347{
3348 using namespace blender;
3350 for (const blender::bke::greasepencil::TreeNode *node : grease_pencil.nodes()) {
3351 names.add(node->name());
3352 }
3353 return names;
3354}
3355
3356static bool check_unique_node_cb(void *arg, const char *name)
3357{
3358 using namespace blender;
3359 VectorSet<StringRefNull> &names = *reinterpret_cast<VectorSet<StringRefNull> *>(arg);
3360 return names.contains(name);
3361}
3362
3364 const char *default_name,
3365 char *name)
3366{
3367 BLI_uniquename_cb(check_unique_node_cb, &names, default_name, '.', name, MAX_NAME);
3368}
3369
3370static std::string unique_node_name(const GreasePencil &grease_pencil,
3371 const char *default_name,
3372 blender::StringRef name)
3373{
3374 using namespace blender;
3375 char unique_name[MAX_NAME];
3376 STRNCPY(unique_name, name.data());
3377 VectorSet<StringRefNull> names = get_node_names(grease_pencil);
3378 unique_node_name_ex(names, default_name, unique_name);
3379 return unique_name;
3380}
3381
3382std::string GreasePencil::unique_layer_name(blender::StringRef name)
3383{
3384 return unique_node_name(*this, DATA_("Layer"), name);
3385}
3386
3387static std::string unique_layer_group_name(const GreasePencil &grease_pencil,
3389{
3390 return unique_node_name(grease_pencil, DATA_("Group"), name);
3391}
3392
3393blender::bke::greasepencil::Layer &GreasePencil::add_layer(const blender::StringRefNull name,
3394 const bool check_name_is_unique)
3395{
3396 using namespace blender;
3397 std::string unique_name = check_name_is_unique ? unique_layer_name(name) : name.c_str();
3398 const int numLayers = layers().size();
3399 CustomData_realloc(&layers_data, numLayers, numLayers + 1, CD_SET_DEFAULT);
3400 bke::greasepencil::Layer *new_layer = MEM_new<bke::greasepencil::Layer>(__func__, unique_name);
3401 /* Hide masks by default. */
3403 bke::greasepencil::Layer &layer = root_group().add_node(new_layer->as_node()).as_layer();
3404
3405 /* Initialize the attributes with default values. */
3406 bke::MutableAttributeAccessor attributes = this->attributes_for_write();
3410 IndexRange::from_single(numLayers));
3411
3412 return layer;
3413}
3414
3415blender::bke::greasepencil::Layer &GreasePencil::add_layer(
3417 const blender::StringRefNull name,
3418 const bool check_name_is_unique)
3419{
3420 using namespace blender;
3421 blender::bke::greasepencil::Layer &new_layer = this->add_layer(name, check_name_is_unique);
3422 move_node_into(new_layer.as_node(), parent_group);
3423 return new_layer;
3424}
3425
3426void GreasePencil::add_layers_for_eval(const int num_new_layers)
3427{
3428 using namespace blender;
3429 const int num_layers = this->layers().size();
3430 CustomData_realloc(&layers_data, num_layers, num_layers + num_new_layers);
3431 for ([[maybe_unused]] const int i : IndexRange(num_new_layers)) {
3432 bke::greasepencil::Layer *new_layer = MEM_new<bke::greasepencil::Layer>(__func__);
3433 /* Hide masks by default. */
3435 this->root_group().add_node(new_layer->as_node());
3436 }
3437}
3438
3439blender::bke::greasepencil::Layer &GreasePencil::duplicate_layer(
3440 const blender::bke::greasepencil::Layer &duplicate_layer)
3441{
3442 using namespace blender;
3443 std::string unique_name = unique_layer_name(duplicate_layer.name());
3444 std::optional<int> duplicate_layer_idx = get_layer_index(duplicate_layer);
3445 const int numLayers = layers().size();
3446 CustomData_realloc(&layers_data, numLayers, numLayers + 1);
3447 if (duplicate_layer_idx.has_value()) {
3448 for (const int layer_index : IndexRange(layers_data.totlayer)) {
3449 CustomData_copy_data_layer(&layers_data,
3450 &layers_data,
3451 layer_index,
3452 layer_index,
3453 *duplicate_layer_idx,
3454 numLayers,
3455 1);
3456 }
3457 }
3458 bke::greasepencil::Layer *new_layer = MEM_new<bke::greasepencil::Layer>(__func__,
3459 duplicate_layer);
3460 root_group().add_node(new_layer->as_node());
3461 this->update_drawing_users_for_layer(*new_layer);
3462 new_layer->set_name(unique_name);
3463 return *new_layer;
3464}
3465
3466blender::bke::greasepencil::Layer &GreasePencil::duplicate_layer(
3468 const blender::bke::greasepencil::Layer &duplicate_layer)
3469{
3470 using namespace blender;
3471 bke::greasepencil::Layer &new_layer = this->duplicate_layer(duplicate_layer);
3472 move_node_into(new_layer.as_node(), parent_group);
3473 return new_layer;
3474}
3475
3476blender::bke::greasepencil::LayerGroup &GreasePencil::add_layer_group(
3477 const blender::StringRefNull name, const bool check_name_is_unique)
3478{
3479 using namespace blender;
3480 std::string unique_name = check_name_is_unique ? unique_layer_group_name(*this, name) :
3481 name.c_str();
3482 bke::greasepencil::LayerGroup *new_group = MEM_new<bke::greasepencil::LayerGroup>(__func__,
3483 unique_name);
3484 return root_group().add_node(new_group->as_node()).as_group();
3485}
3486
3487blender::bke::greasepencil::LayerGroup &GreasePencil::add_layer_group(
3489 const blender::StringRefNull name,
3490 const bool check_name_is_unique)
3491{
3492 using namespace blender;
3493 bke::greasepencil::LayerGroup &new_group = this->add_layer_group(name, check_name_is_unique);
3494 move_node_into(new_group.as_node(), parent_group);
3495 return new_group;
3496}
3497
3498static void reorder_customdata(CustomData &data, const Span<int> new_by_old_map)
3499{
3500 CustomData new_data;
3501 CustomData_init_layout_from(&data, &new_data, CD_MASK_ALL, CD_CONSTRUCT, new_by_old_map.size());
3502
3503 for (const int old_i : new_by_old_map.index_range()) {
3504 const int new_i = new_by_old_map[old_i];
3505 CustomData_copy_data(&data, &new_data, old_i, new_i, 1);
3506 }
3507 CustomData_free(&data, new_by_old_map.size());
3508 data = new_data;
3509}
3510
3511static void reorder_layer_data(GreasePencil &grease_pencil,
3512 const blender::FunctionRef<void()> do_layer_order_changes)
3513{
3514 using namespace blender;
3515 Span<const bke::greasepencil::Layer *> layers = grease_pencil.layers();
3516
3517 /* Stash the initial layer order that we can refer back to later */
3518 Map<const bke::greasepencil::Layer *, int> old_layer_index_by_layer;
3519 old_layer_index_by_layer.reserve(layers.size());
3520 for (const int i : layers.index_range()) {
3521 old_layer_index_by_layer.add_new(layers[i], i);
3522 }
3523
3524 /* Execute the callback that changes the order of the layers. */
3525 do_layer_order_changes();
3526 layers = grease_pencil.layers();
3527 BLI_assert(layers.size() == old_layer_index_by_layer.size());
3528
3529 /* Compose the mapping from old layer indices to new layer indices */
3530 Array<int> new_by_old_map(layers.size());
3531 for (const int layer_i_new : layers.index_range()) {
3532 const bke::greasepencil::Layer *layer = layers[layer_i_new];
3533 BLI_assert(old_layer_index_by_layer.contains(layer));
3534 const int layer_i_old = old_layer_index_by_layer.pop(layer);
3535 new_by_old_map[layer_i_old] = layer_i_new;
3536 }
3537 BLI_assert(old_layer_index_by_layer.is_empty());
3538
3539 /* Use the mapping to re-order the custom data */
3540 reorder_customdata(grease_pencil.layers_data, new_by_old_map);
3541}
3542
3543void GreasePencil::move_node_up(blender::bke::greasepencil::TreeNode &node, const int step)
3544{
3545 using namespace blender;
3546 if (!node.parent_group()) {
3547 return;
3548 }
3549 reorder_layer_data(*this, [&]() { node.parent_group()->move_node_up(node, step); });
3550}
3551void GreasePencil::move_node_down(blender::bke::greasepencil::TreeNode &node, const int step)
3552{
3553 using namespace blender;
3554 if (!node.parent_group()) {
3555 return;
3556 }
3557 reorder_layer_data(*this, [&]() { node.parent_group()->move_node_down(node, step); });
3558}
3559void GreasePencil::move_node_top(blender::bke::greasepencil::TreeNode &node)
3560{
3561 using namespace blender;
3562 if (!node.parent_group()) {
3563 return;
3564 }
3565 reorder_layer_data(*this, [&]() { node.parent_group()->move_node_top(node); });
3566}
3567void GreasePencil::move_node_bottom(blender::bke::greasepencil::TreeNode &node)
3568{
3569 using namespace blender;
3570 if (!node.parent_group()) {
3571 return;
3572 }
3573 reorder_layer_data(*this, [&]() { node.parent_group()->move_node_bottom(node); });
3574}
3575
3576void GreasePencil::move_node_after(blender::bke::greasepencil::TreeNode &node,
3578{
3579 using namespace blender;
3580 if (!target_node.parent_group() || !node.parent_group()) {
3581 return;
3582 }
3583 reorder_layer_data(*this, [&]() {
3584 node.parent_group()->unlink_node(node);
3585 target_node.parent_group()->add_node_after(node, target_node);
3586 });
3587}
3588
3589void GreasePencil::move_node_before(blender::bke::greasepencil::TreeNode &node,
3591{
3592 using namespace blender;
3593 if (!target_node.parent_group() || !node.parent_group()) {
3594 return;
3595 }
3596 reorder_layer_data(*this, [&]() {
3597 node.parent_group()->unlink_node(node);
3598 target_node.parent_group()->add_node_before(node, target_node);
3599 });
3600}
3601
3602void GreasePencil::move_node_into(blender::bke::greasepencil::TreeNode &node,
3604{
3605 using namespace blender;
3606 if (!node.parent_group()) {
3607 return;
3608 }
3609 reorder_layer_data(*this, [&]() {
3610 node.parent_group()->unlink_node(node);
3611 parent_group.add_node(node);
3612 });
3613}
3614
3615const blender::bke::greasepencil::TreeNode *GreasePencil::find_node_by_name(
3616 const blender::StringRefNull name) const
3617{
3618 return this->root_group().find_node_by_name(name);
3619}
3620
3621blender::bke::greasepencil::TreeNode *GreasePencil::find_node_by_name(
3622 const blender::StringRefNull name)
3623{
3624 return this->root_group().find_node_by_name(name);
3625}
3626
3627blender::IndexMask GreasePencil::layer_selection_by_name(const blender::StringRefNull name,
3628 blender::IndexMaskMemory &memory) const
3629{
3630 using namespace blender::bke::greasepencil;
3631 const TreeNode *node = this->find_node_by_name(name);
3632 if (!node) {
3633 return {};
3634 }
3635
3636 if (node->is_layer()) {
3637 const int index = *this->get_layer_index(node->as_layer());
3639 }
3640 if (node->is_group()) {
3641 blender::Vector<int64_t> layer_indices;
3642 for (const int64_t layer_index : this->layers().index_range()) {
3643 const Layer &layer = *this->layers()[layer_index];
3644 if (layer.is_child_of(node->as_group())) {
3645 layer_indices.append(layer_index);
3646 }
3647 }
3648 return blender::IndexMask::from_indices(layer_indices.as_span(), memory);
3649 }
3650 return {};
3651}
3652
3654{
3655 switch (md->type) {
3657 auto *amd = reinterpret_cast<GreasePencilArmatureModifierData *>(md);
3658 return &amd->influence;
3659 }
3661 auto *mmd = reinterpret_cast<GreasePencilArrayModifierData *>(md);
3662 return &mmd->influence;
3663 }
3665 auto *bmd = reinterpret_cast<GreasePencilBuildModifierData *>(md);
3666 return &bmd->influence;
3667 }
3669 auto *cmd = reinterpret_cast<GreasePencilColorModifierData *>(md);
3670 return &cmd->influence;
3671 }
3673 auto *dmd = reinterpret_cast<GreasePencilDashModifierData *>(md);
3674 return &dmd->influence;
3675 }
3677 auto *emd = reinterpret_cast<GreasePencilEnvelopeModifierData *>(md);
3678 return &emd->influence;
3679 }
3681 auto *hmd = reinterpret_cast<GreasePencilHookModifierData *>(md);
3682 return &hmd->influence;
3683 }
3685 auto *lmd = reinterpret_cast<GreasePencilLatticeModifierData *>(md);
3686 return &lmd->influence;
3687 }
3689 auto *lmd = reinterpret_cast<GreasePencilLengthModifierData *>(md);
3690 return &lmd->influence;
3691 }
3693 auto *mmd = reinterpret_cast<GreasePencilMirrorModifierData *>(md);
3694 return &mmd->influence;
3695 }
3697 auto *mmd = reinterpret_cast<GreasePencilMultiModifierData *>(md);
3698 return &mmd->influence;
3699 }
3701 auto *nmd = reinterpret_cast<GreasePencilNoiseModifierData *>(md);
3702 return &nmd->influence;
3703 }
3705 auto *omd = reinterpret_cast<GreasePencilOffsetModifierData *>(md);
3706 return &omd->influence;
3707 }
3709 auto *omd = reinterpret_cast<GreasePencilOpacityModifierData *>(md);
3710 return &omd->influence;
3711 }
3713 auto *omd = reinterpret_cast<GreasePencilOutlineModifierData *>(md);
3714 return &omd->influence;
3715 }
3717 auto *smd = reinterpret_cast<GreasePencilShrinkwrapModifierData *>(md);
3718 return &smd->influence;
3719 }
3721 auto *smd = reinterpret_cast<GreasePencilSimplifyModifierData *>(md);
3722 return &smd->influence;
3723 }
3725 auto *smd = reinterpret_cast<GreasePencilSmoothModifierData *>(md);
3726 return &smd->influence;
3727 }
3729 auto *smd = reinterpret_cast<GreasePencilSubdivModifierData *>(md);
3730 return &smd->influence;
3731 }
3733 auto *tmd = reinterpret_cast<GreasePencilTextureModifierData *>(md);
3734 return &tmd->influence;
3735 }
3737 auto *tmd = reinterpret_cast<GreasePencilThickModifierData *>(md);
3738 return &tmd->influence;
3739 }
3741 auto *tmd = reinterpret_cast<GreasePencilTimeModifierData *>(md);
3742 return &tmd->influence;
3743 }
3745 auto *tmd = reinterpret_cast<GreasePencilTintModifierData *>(md);
3746 return &tmd->influence;
3747 }
3749 auto *wmd = reinterpret_cast<GreasePencilWeightAngleModifierData *>(md);
3750 return &wmd->influence;
3751 }
3753 auto *wmd = reinterpret_cast<GreasePencilWeightProximityModifierData *>(md);
3754 return &wmd->influence;
3755 }
3758 default:
3759 return nullptr;
3760 }
3761 return nullptr;
3762}
3763
3764void GreasePencil::rename_node(Main &bmain,
3766 blender::StringRefNull new_name)
3767{
3768 using namespace blender;
3769 if (node.name() == new_name) {
3770 return;
3771 }
3772
3773 /* Rename the node. */
3774 std::string old_name = node.name();
3775 if (node.is_layer()) {
3776 node.set_name(unique_layer_name(new_name));
3777 }
3778 else if (node.is_group()) {
3779 node.set_name(unique_layer_group_name(*this, new_name));
3780 }
3781
3782 /* Update layer name dependencies. */
3783 if (node.is_layer()) {
3784 BKE_animdata_fix_paths_rename_all(&this->id, "layers", old_name.c_str(), node.name().c_str());
3785 /* Update names in layer masks. */
3786 for (bke::greasepencil::Layer *layer : this->layers_for_write()) {
3787 LISTBASE_FOREACH (GreasePencilLayerMask *, mask, &layer->masks) {
3788 if (STREQ(mask->layer_name, old_name.c_str())) {
3789 mask->layer_name = BLI_strdup(node.name().c_str());
3790 }
3791 }
3792 }
3793 }
3794
3795 /* Update name dependencies outside of the ID. */
3796 LISTBASE_FOREACH (Object *, object, &bmain.objects) {
3797 if (object->data != this) {
3798 continue;
3799 }
3800
3801 /* Update the layer name of the influence data of the modifiers. */
3802 LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
3803 char *dst_layer_name = nullptr;
3804 size_t dst_layer_name_len = 0;
3805 /* LineArt doesn't use the `GreasePencilModifierInfluenceData` struct. */
3806 if (md->type == eModifierType_GreasePencilLineart) {
3807 auto *lmd = reinterpret_cast<GreasePencilLineartModifierData *>(md);
3808 dst_layer_name = lmd->target_layer;
3809 dst_layer_name_len = sizeof(lmd->target_layer);
3810 }
3812 md))
3813 {
3814 dst_layer_name = influence_data->layer_name;
3815 dst_layer_name_len = sizeof(influence_data->layer_name);
3816 }
3817 if (dst_layer_name && STREQ(dst_layer_name, old_name.c_str())) {
3818 BLI_strncpy(dst_layer_name, node.name().c_str(), dst_layer_name_len);
3819 }
3820 }
3821 }
3822}
3823
3824static void shrink_customdata(CustomData &data, const int index_to_remove, const int size)
3825{
3826 using namespace blender;
3827 CustomData new_data;
3828 CustomData_init_layout_from(&data, &new_data, CD_MASK_ALL, CD_CONSTRUCT, size);
3829 CustomData_realloc(&new_data, size, size - 1);
3830
3831 const IndexRange range_before(index_to_remove);
3832 const IndexRange range_after(index_to_remove + 1, size - index_to_remove - 1);
3833
3834 if (!range_before.is_empty()) {
3836 &data, &new_data, range_before.start(), range_before.start(), range_before.size());
3837 }
3838 if (!range_after.is_empty()) {
3840 &data, &new_data, range_after.start(), range_after.start() - 1, range_after.size());
3841 }
3842
3843 CustomData_free(&data, size);
3844 data = new_data;
3845}
3846
3848 GreasePencil &grease_pencil, const blender::bke::greasepencil::TreeNode &node)
3849{
3850 using namespace blender::bke::greasepencil;
3851 /* 1. Try setting the node below (within the same group) to be active. */
3852 if (node.prev != nullptr) {
3853 grease_pencil.set_active_node(reinterpret_cast<TreeNode *>(node.prev));
3854 }
3855 /* 2. If there is no node below, try setting the node above (within the same group) to be the
3856 * active one.*/
3857 else if (node.next != nullptr) {
3858 grease_pencil.set_active_node(reinterpret_cast<TreeNode *>(node.next));
3859 }
3860 /* 3. If this is the only node within its parent group and the parent group is not the root
3861 * group, try setting the parent to be active. */
3862 else if (node.parent != grease_pencil.root_group_ptr) {
3863 grease_pencil.set_active_node(&node.parent->wrap().as_node());
3864 }
3865 /* 4. Otherwise, clear the active node. */
3866 else {
3867 grease_pencil.set_active_node(nullptr);
3868 }
3869}
3870
3871void GreasePencil::remove_layer(blender::bke::greasepencil::Layer &layer)
3872{
3873 using namespace blender::bke::greasepencil;
3874 /* If the layer is active, update the active layer. */
3875 if (&layer.as_node() == this->get_active_node()) {
3876 update_active_node_from_node_to_remove(*this, layer.as_node());
3877 }
3878
3879 /* Remove all the layer attributes and shrink the `CustomData`. */
3880 const int layer_index = *this->get_layer_index(layer);
3881 shrink_customdata(this->layers_data, layer_index, this->layers().size());
3882
3883 /* Unlink the layer from the parent group. */
3884 layer.parent_group().unlink_node(layer.as_node());
3885
3886 /* Remove drawings. */
3887 for (const GreasePencilFrame frame : layer.frames().values()) {
3888 GreasePencilDrawingBase *drawing_base = this->drawing(frame.drawing_index);
3889 if (drawing_base->type != GP_DRAWING) {
3890 /* TODO: Remove drawing reference. */
3891 continue;
3892 }
3893 GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_base);
3894 drawing->wrap().remove_user();
3895 }
3896 this->remove_drawings_with_no_users();
3897
3898 /* Delete the layer. */
3899 MEM_delete(&layer);
3900}
3901
3902void GreasePencil::remove_group(blender::bke::greasepencil::LayerGroup &group,
3903 const bool keep_children)
3904{
3905 using namespace blender::bke::greasepencil;
3906 /* If the group is active, update the active layer. */
3907 if (&group.as_node() == this->get_active_node()) {
3908 /* If we keep the children and there is at least one child, make it the active node. */
3909 if (keep_children && !group.is_empty()) {
3910 this->set_active_node(reinterpret_cast<TreeNode *>(group.children.last));
3911 }
3912 else {
3913 update_active_node_from_node_to_remove(*this, group.as_node());
3914 }
3915 }
3916
3917 if (!keep_children) {
3918 /* Recursively remove groups and layers. */
3919 LISTBASE_FOREACH_MUTABLE (GreasePencilLayerTreeNode *, child, &group.children) {
3920 switch (child->type) {
3921 case GP_LAYER_TREE_LEAF: {
3922 this->remove_layer(reinterpret_cast<GreasePencilLayer *>(child)->wrap());
3923 break;
3924 }
3925 case GP_LAYER_TREE_GROUP: {
3926 this->remove_group(reinterpret_cast<GreasePencilLayerTreeGroup *>(child)->wrap(), false);
3927 break;
3928 }
3929 default:
3931 }
3932 }
3933 BLI_assert(BLI_listbase_is_empty(&group.children));
3934 }
3935
3936 /* Unlink then delete active group node. */
3937 group.as_node().parent_group()->unlink_node(group.as_node(), true);
3938 MEM_delete(&group);
3939}
3940
3941void GreasePencil::print_layer_tree()
3942{
3943 using namespace blender::bke::greasepencil;
3944 this->root_group().print_nodes("Layer Tree:");
3945}
3946
3949/* ------------------------------------------------------------------- */
3953static void read_drawing_array(GreasePencil &grease_pencil, BlendDataReader *reader)
3954{
3956 grease_pencil.drawing_array_num,
3957 reinterpret_cast<void **>(&grease_pencil.drawing_array));
3958 for (int i = 0; i < grease_pencil.drawing_array_num; i++) {
3959 BLO_read_struct(reader, GreasePencilDrawingBase, &grease_pencil.drawing_array[i]);
3960 GreasePencilDrawingBase *drawing_base = grease_pencil.drawing_array[i];
3961 switch (GreasePencilDrawingType(drawing_base->type)) {
3962 case GP_DRAWING: {
3963 GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_base);
3964 drawing->wrap().strokes_for_write().blend_read(*reader);
3965 /* Initialize runtime data. */
3966 drawing->runtime = MEM_new<blender::bke::greasepencil::DrawingRuntime>(__func__);
3967 break;
3968 }
3969 case GP_DRAWING_REFERENCE: {
3970 break;
3971 }
3972 }
3973 }
3974}
3975
3976static void write_drawing_array(GreasePencil &grease_pencil, BlendWriter *writer)
3977{
3978 using namespace blender;
3979 BLO_write_pointer_array(writer, grease_pencil.drawing_array_num, grease_pencil.drawing_array);
3980 for (int i = 0; i < grease_pencil.drawing_array_num; i++) {
3981 GreasePencilDrawingBase *drawing_base = grease_pencil.drawing_array[i];
3982 switch (GreasePencilDrawingType(drawing_base->type)) {
3983 case GP_DRAWING: {
3984 GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_base);
3985 bke::CurvesGeometry::BlendWriteData write_data =
3986 drawing->wrap().strokes_for_write().blend_write_prepare();
3987 BLO_write_struct(writer, GreasePencilDrawing, drawing);
3988 drawing->wrap().strokes_for_write().blend_write(*writer, grease_pencil.id, write_data);
3989 break;
3990 }
3991 case GP_DRAWING_REFERENCE: {
3992 GreasePencilDrawingReference *drawing_reference =
3993 reinterpret_cast<GreasePencilDrawingReference *>(drawing_base);
3994 BLO_write_struct(writer, GreasePencilDrawingReference, drawing_reference);
3995 break;
3996 }
3997 }
3998 }
3999}
4000
4001static void free_drawing_array(GreasePencil &grease_pencil)
4002{
4003 grease_pencil.resize_drawings(0);
4004}
4005
4008/* ------------------------------------------------------------------- */
4012static void read_layer(BlendDataReader *reader,
4013 GreasePencilLayer *node,
4015{
4016 BLO_read_string(reader, &node->base.name);
4017 node->base.parent = parent;
4018 BLO_read_string(reader, &node->parsubstr);
4019 BLO_read_string(reader, &node->viewlayername);
4020
4021 /* Read frames storage. */
4022 BLO_read_int32_array(reader, node->frames_storage.num, &node->frames_storage.keys);
4024 reader, GreasePencilFrame, node->frames_storage.num, &node->frames_storage.values);
4025
4026 /* Read layer masks. */
4027 BLO_read_struct_list(reader, GreasePencilLayerMask, &node->masks);
4028 LISTBASE_FOREACH (GreasePencilLayerMask *, mask, &node->masks) {
4029 BLO_read_string(reader, &mask->layer_name);
4030 }
4031
4032 /* NOTE: Ideally this should be cleared on write, to reduce false 'changes' detection in memfile
4033 * undo system. This is not easily doable currently though, since modifying to actual data during
4034 * write is not an option (a shallow copy of the #Layer data would be needed then). */
4035 node->runtime = nullptr;
4036 node->wrap().update_from_dna_read();
4037}
4038
4042{
4043 BLO_read_string(reader, &node->base.name);
4044 node->base.parent = parent;
4045 /* Read list of children. */
4046 BLO_read_struct_list(reader, GreasePencilLayerTreeNode, &node->children);
4047 LISTBASE_FOREACH (GreasePencilLayerTreeNode *, child, &node->children) {
4048 switch (child->type) {
4049 case GP_LAYER_TREE_LEAF: {
4050 GreasePencilLayer *layer = reinterpret_cast<GreasePencilLayer *>(child);
4051 read_layer(reader, layer, node);
4052 break;
4053 }
4054 case GP_LAYER_TREE_GROUP: {
4055 GreasePencilLayerTreeGroup *group = reinterpret_cast<GreasePencilLayerTreeGroup *>(child);
4056 read_layer_tree_group(reader, group, node);
4057 break;
4058 }
4059 }
4060 }
4061
4062 node->wrap().runtime = MEM_new<blender::bke::greasepencil::LayerGroupRuntime>(__func__);
4063}
4064
4065static void read_layer_tree(GreasePencil &grease_pencil, BlendDataReader *reader)
4066{
4067 /* Read root group. */
4069 /* This shouldn't normally happen, but for files that were created before the root group became a
4070 * pointer, this address will not exist. In this case, we clear the pointer to the active layer
4071 * and create an empty root group to avoid crashes. */
4072 if (grease_pencil.root_group_ptr == nullptr) {
4073 grease_pencil.root_group_ptr = MEM_new<blender::bke::greasepencil::LayerGroup>(__func__);
4074 grease_pencil.set_active_node(nullptr);
4075 return;
4076 }
4077 /* Read active layer. */
4078 BLO_read_struct(reader, GreasePencilLayerTreeNode, &grease_pencil.active_node);
4079 read_layer_tree_group(reader, grease_pencil.root_group_ptr, nullptr);
4080
4081 grease_pencil.root_group_ptr->wrap().update_from_dna_read();
4082}
4083
4084static void write_layer(BlendWriter *writer, GreasePencilLayer *node)
4085{
4086 BLO_write_struct(writer, GreasePencilLayer, node);
4087 BLO_write_string(writer, node->base.name);
4088 BLO_write_string(writer, node->parsubstr);
4089 BLO_write_string(writer, node->viewlayername);
4090
4091 BLO_write_int32_array(writer, node->frames_storage.num, node->frames_storage.keys);
4093 writer, GreasePencilFrame, node->frames_storage.num, node->frames_storage.values);
4094
4095 BLO_write_struct_list(writer, GreasePencilLayerMask, &node->masks);
4096 LISTBASE_FOREACH (GreasePencilLayerMask *, mask, &node->masks) {
4097 BLO_write_string(writer, mask->layer_name);
4098 }
4099}
4100
4102{
4104 BLO_write_string(writer, node->base.name);
4105 LISTBASE_FOREACH (GreasePencilLayerTreeNode *, child, &node->children) {
4106 switch (child->type) {
4107 case GP_LAYER_TREE_LEAF: {
4108 GreasePencilLayer *layer = reinterpret_cast<GreasePencilLayer *>(child);
4109 write_layer(writer, layer);
4110 break;
4111 }
4112 case GP_LAYER_TREE_GROUP: {
4113 GreasePencilLayerTreeGroup *group = reinterpret_cast<GreasePencilLayerTreeGroup *>(child);
4114 write_layer_tree_group(writer, group);
4115 break;
4116 }
4117 }
4118 }
4119}
4120
4121static void write_layer_tree(GreasePencil &grease_pencil, BlendWriter *writer)
4122{
4123 grease_pencil.root_group_ptr->wrap().prepare_for_dna_write();
4124 write_layer_tree_group(writer, grease_pencil.root_group_ptr);
4125}
Blender kernel action and pose functionality.
bPoseChannel * BKE_pose_channel_find_name(const bPose *pose, const char *name)
void BKE_animdata_free(ID *id, bool do_id_user)
Definition anim_data.cc:263
void BKE_animdata_fix_paths_rename_all(struct ID *ref_id, const char *prefix, const char *oldName, const char *newName)
Low-level operations for curves.
CustomData interface, see also DNA_customdata_types.h.
void CustomData_blend_write_prepare(CustomData &data, blender::Vector< CustomDataLayer, 16 > &layers_to_write, const blender::Set< std::string > &skip_names={})
void CustomData_realloc(CustomData *data, int old_size, int new_size, eCDAllocType alloctype=CD_CONSTRUCT)
void * CustomData_get_layer_named_for_write(CustomData *data, eCustomDataType type, blender::StringRef name, int totelem)
@ CD_SET_DEFAULT
@ CD_CONSTRUCT
void * CustomData_add_layer_named(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem, blender::StringRef name)
void CustomData_reset(CustomData *data)
void CustomData_blend_write(BlendWriter *writer, CustomData *data, blender::Span< CustomDataLayer > layers_to_write, int count, eCustomDataMask cddata_mask, ID *id)
void CustomData_copy_data_layer(const CustomData *source, CustomData *dest, int src_layer_index, int dst_layer_index, int src_index, int dst_index, int count)
void CustomData_init_from(const CustomData *source, CustomData *dest, eCustomDataMask mask, int totelem)
void CustomData_free(CustomData *data, int totelem)
void CustomData_blend_read(BlendDataReader *reader, CustomData *data, int count)
void CustomData_init_layout_from(const CustomData *source, CustomData *dest, eCustomDataMask mask, eCDAllocType alloctype, int totelem)
void CustomData_copy_data(const CustomData *source, CustomData *dest, int source_index, int dest_index, int count)
support for deformation groups and hooks.
void BKE_defbase_blend_write(BlendWriter *writer, const ListBase *defbase)
Definition deform.cc:1635
void BKE_defgroup_copy_list(ListBase *outbase, const ListBase *inbase)
Definition deform.cc:76
Low-level operations for grease pencil that cannot be defined in the C++ header yet.
void(* BKE_grease_pencil_batch_cache_dirty_tag_cb)(GreasePencil *grease_pencil, int mode)
void BKE_grease_pencil_batch_cache_dirty_tag(GreasePencil *grease_pencil, int mode)
void BKE_grease_pencil_batch_cache_free(GreasePencil *grease_pencil)
void(* BKE_grease_pencil_batch_cache_free_cb)(GreasePencil *grease_pencil)
Low-level operations for grease pencil.
void BKE_grease_pencil_point_coords_get(const GreasePencil &grease_pencil, GreasePencilPointCoordinates *elem_data)
void * BKE_grease_pencil_add(Main *bmain, const char *name)
Material * BKE_grease_pencil_object_material_ensure_from_active_input_brush(Main *bmain, Object *ob, Brush *brush)
void BKE_grease_pencil_copy_parameters(const GreasePencil &src, GreasePencil &dst)
void BKE_grease_pencil_material_remap(GreasePencil *grease_pencil, const uint *remap, int totcol)
void BKE_grease_pencil_material_index_remove(GreasePencil *grease_pencil, int index)
Material * BKE_grease_pencil_object_material_ensure_active(Object *ob)
void BKE_grease_pencil_point_coords_apply_with_mat4(GreasePencil &grease_pencil, GreasePencilPointCoordinates *elem_data, const blender::float4x4 &mat)
void BKE_grease_pencil_vgroup_name_update(Object *ob, const char *old_name, const char *new_name)
void BKE_grease_pencil_point_coords_apply(GreasePencil &grease_pencil, GreasePencilPointCoordinates *elem_data)
bool BKE_grease_pencil_references_cyclic_check(const GreasePencil *id_reference, const GreasePencil *grease_pencil)
Material * BKE_grease_pencil_object_material_new(Main *bmain, Object *ob, const char *name, int *r_index)
Material * BKE_grease_pencil_object_material_ensure_from_brush(Main *bmain, Object *ob, Brush *brush)
void BKE_grease_pencil_data_update(Depsgraph *depsgraph, Scene *scene, Object *object)
void BKE_grease_pencil_nomain_to_grease_pencil(GreasePencil *grease_pencil_src, GreasePencil *grease_pencil_dst)
bool BKE_grease_pencil_drawing_attribute_required(const GreasePencilDrawing *, const char *name)
Material * BKE_grease_pencil_object_material_ensure_from_active_input_material(Object *ob)
void BKE_grease_pencil_duplicate_drawing_array(const GreasePencil *grease_pencil_src, GreasePencil *grease_pencil_dst)
Material * BKE_grease_pencil_object_material_from_brush_get(Object *ob, Brush *brush)
Material * BKE_grease_pencil_brush_material_get(Brush *brush)
int BKE_grease_pencil_stroke_point_count(const GreasePencil &grease_pencil)
GreasePencil * BKE_grease_pencil_new_nomain()
void BKE_grease_pencil_copy_layer_parameters(const blender::bke::greasepencil::Layer &src, blender::bke::greasepencil::Layer &dst)
void BKE_grease_pencil_copy_layer_group_parameters(const blender::bke::greasepencil::LayerGroup &src, blender::bke::greasepencil::LayerGroup &dst)
GreasePencil * BKE_grease_pencil_copy_for_eval(const GreasePencil *grease_pencil_src)
bool BKE_grease_pencil_material_index_used(GreasePencil *grease_pencil, int index)
int BKE_grease_pencil_object_material_index_get_by_name(Object *ob, const char *name)
Material * BKE_grease_pencil_object_material_ensure_by_name(Main *bmain, Object *ob, const char *name, int *r_index)
@ IDTYPE_FLAGS_APPEND_IS_REUSABLE
Definition BKE_idtype.hh:39
@ LIB_ID_COPY_LOCALIZE
void BKE_id_free(Main *bmain, void *idv)
ID * BKE_id_copy_ex(Main *bmain, const ID *id, ID **new_id_p, int flag)
Definition lib_id.cc:760
void * BKE_id_new(Main *bmain, short type, const char *name)
Definition lib_id.cc:1482
void id_us_min(ID *id)
Definition lib_id.cc:359
void * BKE_id_new_nomain(short type, const char *name)
Definition lib_id.cc:1487
void BKE_id_blend_write(BlendWriter *writer, ID *id)
Definition lib_id.cc:2560
#define BKE_LIB_FOREACHID_PROCESS_IDSUPER(data_, id_super_, cb_flag_)
@ IDWALK_CB_USER
General operations, lookup, etc. for materials.
struct Material * BKE_gpencil_material_add(struct Main *bmain, const char *name)
struct Material * BKE_object_material_get(struct Object *ob, short act)
short * BKE_object_material_len_p(struct Object *ob)
void BKE_object_material_assign(struct Main *bmain, struct Object *ob, struct Material *ma, short act, int assign_type)
@ BKE_MAT_ASSIGN_USERPREF
void BKE_gpencil_material_attr_init(struct Material *ma)
bool BKE_object_material_slot_add(struct Main *bmain, struct Object *ob)
int BKE_object_material_index_get(Object *ob, const Material *ma)
struct Material * BKE_material_default_gpencil(void)
void BKE_modifiers_clear_errors(Object *ob)
bool BKE_modifier_is_enabled(const Scene *scene, ModifierData *md, int required_mode)
const ModifierTypeInfo * BKE_modifier_get_info(ModifierType type)
ModifierData * BKE_modifiers_get_virtual_modifierlist(const Object *ob, VirtualModifierData *data)
ModifierApplyFlag
@ MOD_APPLY_USECACHE
@ MOD_APPLY_RENDER
General operations, lookup, etc. for blender objects.
bool BKE_object_is_in_editmode(const Object *ob)
void BKE_object_eval_assign_data(Object *object, ID *data, bool is_owned)
void BKE_object_free_derived_caches(Object *ob)
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define ATTR_FALLTHROUGH
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
#define LISTBASE_FOREACH_BACKWARD(type, var, list)
void void void void void void BLI_duplicatelist(struct ListBase *dst, const struct ListBase *src) ATTR_NONNULL(1
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:331
bool BLI_remlink_safe(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:153
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
void void void bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step) ATTR_NONNULL()
Definition listbase.cc:435
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:370
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
Normal to x,y matrix.
float mat4_to_scale(const float mat[4][4])
void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3])
void unit_m4(float m[4][4])
Definition rct.c:1127
void copy_m4_m4(float m1[4][4], const float m2[4][4])
MINLINE void add_newell_cross_v3_v3v3(float n[3], const float v_prev[3], const float v_curr[3])
MINLINE void copy_v3_v3_uchar(unsigned char r[3], const unsigned char a[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void copy_v3_fl(float r[3], float f)
MINLINE void zero_v3(float r[3])
void * BLI_memarena_alloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1)
struct MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
#define BLI_MEMARENA_STD_BUFSIZE
void void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1)
void BLI_polyfill_calc_arena(const float(*coords)[2], unsigned int coords_num, int coords_sign, unsigned int(*r_tris)[3], struct MemArena *arena)
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.c:40
#define STRNCPY(dst, src)
Definition BLI_string.h:593
char * BLI_strdup_null(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_MALLOC
Definition string.c:45
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
size_t void BLI_uniquename_cb(UniquenameCheckCallback unique_check, void *arg, const char *defname, char delim, char *name, size_t name_maxncpy) ATTR_NONNULL(1
unsigned int uint
#define UNUSED_VARS_NDEBUG(...)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define STREQ(a, b)
void BLO_write_int32_array(BlendWriter *writer, uint num, const int32_t *data_ptr)
void BLO_read_int32_array(BlendDataReader *reader, int array_size, int32_t **ptr_p)
Definition readfile.cc:4947
#define BLO_write_id_struct(writer, struct_name, id_address, id)
#define BLO_write_struct(writer, struct_name, data_ptr)
void BLO_read_string(BlendDataReader *reader, char **ptr_p)
Definition readfile.cc:4992
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
#define BLO_read_struct_list(reader, struct_name, list)
#define BLO_read_struct_array(reader, struct_name, array_size, ptr_p)
#define BLO_write_struct_list(writer, struct_name, list_ptr)
void BLO_read_pointer_array(BlendDataReader *reader, int array_size, void **ptr_p)
Definition readfile.cc:5052
#define BLO_read_struct(reader, struct_name, ptr_p)
void BLO_write_pointer_array(BlendWriter *writer, uint num, const void *data_ptr)
#define BLT_I18NCONTEXT_ID_GPENCIL
#define DATA_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ DAG_EVAL_RENDER
float DEG_get_ctime(const Depsgraph *graph)
eEvaluationMode DEG_get_mode(const Depsgraph *graph)
Object * DEG_get_original_object(Object *object)
ID and Library types, which are fundamental for SDNA.
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
#define FILTER_ID_MA
Definition DNA_ID.h:1175
@ INDEX_ID_GP
Definition DNA_ID.h:1304
#define FILTER_ID_GP
Definition DNA_ID.h:1203
Enumerations for DNA_ID.h.
@ ID_GP
@ GP_BRUSH_MATERIAL_PINNED
eBezTriple_KeyframeType
#define CD_MASK_ALL
#define DNA_struct_default_get(struct_name)
#define MAX_NAME
Definition DNA_defs.h:50
@ GP_LAYER_BLEND_NONE
@ GP_LAYER_FRAMES_STORAGE_DIRTY
@ LAYERGROUP_COLOR_NONE
struct GreasePencil GreasePencil
GreasePencilLayerTreeNodeType
@ GP_LAYER_TREE_GROUP
@ GP_FRAME_IMPLICIT_HOLD
@ GP_LAYER_TREE_NODE_HIDE_MASKS
GreasePencilDrawingType
@ GP_DRAWING_REFERENCE
@ GREASE_PENCIL_AUTOLOCK_LAYERS
@ eModifierMode_Render
@ eModifierMode_Editmode
@ eModifierMode_Realtime
@ eModifierType_GreasePencilSmooth
@ eModifierType_GreasePencilWeightProximity
@ eModifierType_GreasePencilMirror
@ eModifierType_GreasePencilOffset
@ eModifierType_GreasePencilThickness
@ eModifierType_GreasePencilEnvelope
@ eModifierType_GreasePencilArmature
@ eModifierType_GreasePencilSubdiv
@ eModifierType_GreasePencilTint
@ eModifierType_GreasePencilNoise
@ eModifierType_GreasePencilMultiply
@ eModifierType_GreasePencilBuild
@ eModifierType_GreasePencilTime
@ eModifierType_GreasePencilTexture
@ eModifierType_GreasePencilSimplify
@ eModifierType_GreasePencilColor
@ eModifierType_GreasePencilDash
@ eModifierType_GreasePencilLineart
@ eModifierType_GreasePencilOutline
@ eModifierType_GreasePencilWeightAngle
@ eModifierType_GreasePencilOpacity
@ eModifierType_GreasePencilLength
@ eModifierType_GreasePencilShrinkwrap
@ eModifierType_GreasePencilLattice
@ eModifierType_GreasePencilHook
@ eModifierType_GreasePencilArray
@ OB_MODE_EDIT
@ OB_ARMATURE
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
static const char * ATTR_POSITION
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
btMatrix3x3 transpose() const
Return the transpose of the matrix.
btScalar determinant() const
Return the determinant of the matrix.
SIMD_FORCE_INLINE btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition btVector3.h:303
SIMD_FORCE_INLINE btScalar length() const
Return the length of the vector.
Definition btVector3.h:257
Span< T > as_span() const
Definition BLI_array.hh:232
static const CPPType & get()
constexpr int64_t size() const
constexpr bool is_empty() const
constexpr int64_t start() const
constexpr IndexRange take_back(int64_t n) const
static constexpr IndexRange from_single(const int64_t index)
constexpr IndexRange drop_front(int64_t n) const
const Value * lookup_ptr(const Key &key) const
Definition BLI_map.hh:484
KeyIterator keys() const
Definition BLI_map.hh:837
bool add_overwrite(const Key &key, const Value &value)
Definition BLI_map.hh:301
const Value & lookup(const Key &key) const
Definition BLI_map.hh:506
void remove_contained(const Key &key)
Definition BLI_map.hh:363
void clear_and_shrink()
Definition BLI_map.hh:1003
void add_new(const Key &key, const Value &value)
Definition BLI_map.hh:241
bool contains(const Key &key) const
Definition BLI_map.hh:329
constexpr int64_t size() const
Definition BLI_span.hh:494
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:574
constexpr bool is_empty() const
Definition BLI_span.hh:510
constexpr T * data() const
Definition BLI_span.hh:540
constexpr void fill(const T &value) const
Definition BLI_span.hh:518
constexpr MutableSpan drop_front(const int64_t n) const
Definition BLI_span.hh:608
constexpr T & first() const
Definition BLI_span.hh:680
constexpr IndexRange index_range() const
Definition BLI_span.hh:671
constexpr const T * data() const
Definition BLI_span.hh:216
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
constexpr bool contains(const T &value) const
Definition BLI_span.hh:278
bool is_empty() const
Definition BLI_stack.hh:308
void push(const T &value)
Definition BLI_stack.hh:213
constexpr const char * c_str() const
bool add(const Key &key)
bool contains(const Key &key) const
void append(const T &value)
const T & last(const int64_t n=0) const
void resize(const int64_t new_size)
MutableSpan< T > as_mutable_span()
void reinitialize(const int64_t new_size)
Span< T > as_span() const
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const void *default_value=nullptr) const
bool contains(const StringRef attribute_id) const
MutableAttributeAccessor attributes_for_write()
void count_memory(MemoryCounter &memory) const
std::unique_ptr< GreasePencilEditHints > grease_pencil_edit_hints_
std::optional< MutableSpan< float3 > > positions_for_write()
std::optional< Span< float3 > > positions() const
VArray< ColorGeometry4f > vertex_colors() const
Drawing & operator=(const Drawing &other)
Span< float3 > curve_plane_normals() const
MutableSpan< float > opacities_for_write()
Span< float4x2 > texture_matrices() const
MutableSpan< float > radii_for_write()
bke::CurvesGeometry & strokes_for_write()
const bke::CurvesGeometry & strokes() const
VArray< ColorGeometry4f > fill_colors() const
VArray< float > opacities() const
MutableSpan< ColorGeometry4f > fill_colors_for_write()
MutableSpan< ColorGeometry4f > vertex_colors_for_write()
void set_texture_matrices(Span< float4x2 > matrices, const IndexMask &selection)
TreeNode & add_node(TreeNode &node)
void move_node_down(TreeNode &node, int step=1)
bool unlink_node(TreeNode &link, bool keep_children=false)
Span< const Layer * > layers() const
void add_node_before(TreeNode &node, TreeNode &link)
void add_node_after(TreeNode &node, TreeNode &link)
void move_node_up(TreeNode &node, int step=1)
void print_nodes(StringRefNull header) const
LayerGroup & operator=(const LayerGroup &other)
Span< const LayerGroup * > groups() const
Span< const TreeNode * > nodes() const
const TreeNode * find_node_by_name(StringRefNull name) const
SharedCache< Vector< FramesMapKeyT > > sorted_keys_cache_
Map< FramesMapKeyT, GreasePencilFrame > frames_
SortedKeysIterator sorted_keys_iterator_at(int frame_number) const
void set_parent_bone_name(const char *new_name)
StringRefNull parent_bone_name() const
int sorted_keys_index_at(int frame_number) const
float4x4 to_world_space(const Object &object) const
StringRefNull view_layer_name() const
void set_local_transform(const float4x4 &transform)
void set_view_layer_name(const char *new_name)
bool remove_frame(FramesMapKeyT key)
const Map< FramesMapKeyT, GreasePencilFrame > & frames() const
GreasePencilFrame * add_frame(FramesMapKeyT key, int duration=0)
const GreasePencilFrame * frame_at(const int frame_number) const
bool has_drawing_at(const int frame_number) const
int drawing_index_at(const int frame_number) const
int get_frame_duration_at(const int frame_number) const
std::optional< int > start_frame_at(int frame_number) const
float4x4 to_object_space(const Object &object) const
Span< FramesMapKeyT > sorted_keys() const
Map< FramesMapKeyT, GreasePencilFrame > & frames_for_write()
const TreeNode * parent_node() const
const LayerGroup & as_group() const
const LayerGroup * parent_group() const
static IndexMask from_indices(Span< T > indices, IndexMaskMemory &memory)
IndexMask complement(const IndexMask &universe, IndexMaskMemory &memory) const
void foreach_index(Fn &&fn) const
void foreach_segment(Fn &&fn) const
OperationNode * node
const Depsgraph * depsgraph
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
#define rot(x, k)
static void shrink_array(T **array, int *num, const int shrink_num)
static void transform_positions(const Span< blender::float3 > src, const blender::float4x4 &transform, blender::MutableSpan< blender::float3 > dst)
static void read_layer_tree_group(BlendDataReader *reader, GreasePencilLayerTreeGroup *node, GreasePencilLayerTreeGroup *parent)
static void read_drawing_array(GreasePencil &grease_pencil, BlendDataReader *reader)
static std::string unique_node_name(const GreasePencil &grease_pencil, const char *default_name, blender::StringRef name)
static GreasePencilModifierInfluenceData * influence_data_from_modifier(ModifierData *md)
static void grow_array(T **array, int *num, const int add_num)
static bool grease_pencil_references_cyclic_check_internal(const GreasePencil *id_reference, const GreasePencil *grease_pencil)
static void grease_pencil_free_data(ID *id)
static blender::VectorSet< blender::StringRefNull > get_node_names(const GreasePencil &grease_pencil)
static bool check_unique_node_cb(void *arg, const char *name)
static void reorder_layer_data(GreasePencil &grease_pencil, const blender::FunctionRef< void()> do_layer_order_changes)
static void free_drawing_array(GreasePencil &grease_pencil)
static void write_layer_tree_group(BlendWriter *writer, GreasePencilLayerTreeGroup *node)
static void update_active_node_from_node_to_remove(GreasePencil &grease_pencil, const blender::bke::greasepencil::TreeNode &node)
static void grease_pencil_do_layer_adjustments(GreasePencil &grease_pencil)
static const char * ATTR_POSITION
static void shrink_customdata(CustomData &data, const int index_to_remove, const int size)
static void grease_pencil_copy_data(Main *, std::optional< Library * >, ID *id_dst, const ID *id_src, const int)
void BKE_grease_pencil_batch_cache_free(GreasePencil *grease_pencil)
static void reorder_customdata(CustomData &data, const Span< int > new_by_old_map)
static void read_layer_tree(GreasePencil &grease_pencil, BlendDataReader *reader)
static void write_layer(BlendWriter *writer, GreasePencilLayer *node)
IDTypeInfo IDType_ID_GP
static void write_layer_tree(GreasePencil &grease_pencil, BlendWriter *writer)
static void delete_drawing(GreasePencilDrawingBase *drawing_base)
static void grease_pencil_blend_read_data(BlendDataReader *reader, ID *id)
void BKE_grease_pencil_duplicate_drawing_array(const GreasePencil *grease_pencil_src, GreasePencil *grease_pencil_dst)
static void grease_pencil_foreach_id(ID *id, LibraryForeachIDData *data)
static void grease_pencil_blend_write(BlendWriter *writer, ID *id, const void *id_address)
static void write_drawing_array(GreasePencil &grease_pencil, BlendWriter *writer)
static void unique_node_name_ex(VectorSet< blender::StringRefNull > &names, const char *default_name, char *name)
static void grease_pencil_init_data(ID *id)
static void read_layer(BlendDataReader *reader, GreasePencilLayer *node, GreasePencilLayerTreeGroup *parent)
static void grease_pencil_evaluate_modifiers(Depsgraph *depsgraph, Scene *scene, Object *object, blender::bke::GeometrySet &geometry_set)
static std::string unique_layer_group_name(const GreasePencil &grease_pencil, blender::StringRefNull name)
CCL_NAMESPACE_BEGIN ccl_device float invert(float color, float factor)
Definition invert.h:9
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
ccl_device_inline float cross(const float2 a, const float2 b)
ccl_device_inline float3 cos(float3 v)
static ulong * next
#define T
GAttributeReader lookup(const void *owner, const StringRef attribute_id)
static const std::string ATTR_OPACITY
static void update_curve_plane_normal_cache(const Span< float3 > positions, const OffsetIndices< int > points_by_curve, const IndexMask &curve_mask, MutableSpan< float3 > normals)
static void update_triangle_cache(const Span< float3 > positions, const Span< float3 > normals, const OffsetIndices< int > points_by_curve, const OffsetIndices< int > triangle_offsets, const IndexMask &curve_mask, MutableSpan< uint3 > triangles)
static const std::string ATTR_RADIUS
static int domain_num(const CurvesGeometry &curves, const AttrDomain domain)
static CustomData & domain_custom_data(CurvesGeometry &curves, const AttrDomain domain)
static const std::string ATTR_VERTEX_COLOR
static float4x2 get_local_to_stroke_matrix(const Span< float3 > positions, const float3 normal)
static MutableSpan< T > get_mutable_attribute(CurvesGeometry &curves, const AttrDomain domain, const StringRef name, const T default_value=T())
static float3x2 get_stroke_to_texture_matrix(const float uv_rotation, const float2 uv_translation, const float2 uv_scale)
static float4x3 expand_4x2_mat(float4x2 strokemat)
static const std::string ATTR_FILL_COLOR
void copy_drawing_array(Span< const GreasePencilDrawingBase * > src_drawings, MutableSpan< GreasePencilDrawingBase * > dst_drawings)
static MutableSpan< T > get_mutable_attribute(CurvesGeometry &curves, const AttrDomain domain, const StringRef name, const T default_value=T())
auto attribute_filter_from_skip_ref(const Span< StringRef > skip)
void fill_attribute_range_default(MutableAttributeAccessor dst_attributes, AttrDomain domain, const AttributeFilter &attribute_filter, IndexRange range)
eCustomDataType cpp_type_to_custom_data_type(const CPPType &type)
static const std::string ATTR_RADIUS
Bounds< T > merge(const Bounds< T > &a, const Bounds< T > &b)
Definition BLI_bounds.hh:24
std::optional< Bounds< T > > min_max(const std::optional< Bounds< T > > &a, const T &b)
Definition BLI_bounds.hh:46
T length_squared(const VecBase< T, Size > &a)
T distance(const T &a, const T &b)
QuaternionBase< T > normalize_and_get_length(const QuaternionBase< T > &q, T &out_length)
bool is_zero(const T &a)
CartesianBasis invert(const CartesianBasis &basis)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
void to_loc_rot_scale_safe(const MatBase< T, 4, 4 > &mat, VecBase< T, 3 > &r_location, RotationT &r_rotation, VecBase< T, 3 > &r_scale)
MatT from_loc_rot_scale(const typename MatT::loc_type &location, const RotationT &rotation, const VecBase< typename MatT::base_type, ScaleDim > &scale)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
void parallel_for_each(Range &&range, const Function &function)
Definition BLI_task.hh:58
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
MatBase< double, 4, 2 > double4x2
MatBase< float, 2, 2 > float2x2
MatBase< float, 2, 4 > float2x4
VecBase< float, 4 > float4
MatView< float, 4, 4, 4, 4, 0, 0, alignof(float)> float4x4_view
VecBase< float, 2 > float2
MatBase< float, 3, 2 > float3x2
MatBase< float, 4, 3 > float4x3
void uninitialized_relocate_n(T *src, int64_t n, T *dst)
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
Definition BLI_color.hh:337
VecBase< float, 3 > float3
MatBase< double, 4, 3 > double4x3
void uninitialized_move_n(T *src, int64_t n, T *dst)
float wrap(float value, float max, float min)
Definition node_math.h:71
static void unique_name(bNode *node)
unsigned int uint32_t
Definition stdint.h:80
__int64 int64_t
Definition stdint.h:89
signed char int8_t
Definition stdint.h:75
struct Material * material
struct BrushGpencilSettings * gpencil_settings
CurvesGeometryRuntimeHandle * runtime
GreasePencilModifierInfluenceData influence
GreasePencilModifierInfluenceData influence
GreasePencilModifierInfluenceData influence
GreasePencilModifierInfluenceData influence
GreasePencilModifierInfluenceData influence
GreasePencilDrawingBase base
GreasePencilDrawingRuntimeHandle * runtime
GreasePencilModifierInfluenceData influence
GreasePencilModifierInfluenceData influence
GreasePencilModifierInfluenceData influence
GreasePencilLayerTreeNode base
GreasePencilLayerGroupRuntimeHandle * runtime
struct GreasePencilLayerTreeNode * next
struct GreasePencilLayerTreeNode * prev
struct GreasePencilLayerTreeGroup * parent
GreasePencilLayerRuntimeHandle * runtime
GreasePencilLayerTreeNode base
GreasePencilLayerFramesMapStorage frames_storage
GreasePencilModifierInfluenceData influence
GreasePencilModifierInfluenceData influence
GreasePencilModifierInfluenceData influence
GreasePencilModifierInfluenceData influence
GreasePencilModifierInfluenceData influence
GreasePencilModifierInfluenceData influence
GreasePencilModifierInfluenceData influence
GreasePencilModifierInfluenceData influence
GreasePencilModifierInfluenceData influence
GreasePencilModifierInfluenceData influence
GreasePencilModifierInfluenceData influence
GreasePencilModifierInfluenceData influence
GreasePencilModifierInfluenceData influence
GreasePencilModifierInfluenceData influence
GreasePencilModifierInfluenceData influence
GreasePencilModifierInfluenceData influence
GreasePencilModifierInfluenceData influence
GreasePencilLayerTreeNode * active_node
struct Material ** material_array
GreasePencilLayerTreeGroup * root_group_ptr
GreasePencilRuntimeHandle * runtime
GreasePencilDrawingBase ** drawing_array
GreasePencilOnionSkinningSettings onion_skinning_settings
Definition DNA_ID.h:413
char name[66]
Definition DNA_ID.h:425
void * last
void * first
ListBase objects
Definition BKE_main.hh:212
struct MaterialGPencilStyle * gp_style
struct ModifierData * next
void(* modify_geometry_set)(ModifierData *md, const ModifierEvalContext *ctx, blender::bke::GeometrySet *geometry_set)
struct bPose * pose
const c_style_mat & ptr() const
GeometryComponent & get_component_for_write(GeometryComponent::Type component_type)
const GreasePencil * get_grease_pencil() const
GreasePencil * get_grease_pencil_for_write()
void replace_grease_pencil(GreasePencil *grease_pencil, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4126
uint8_t flag
Definition wm_window.cc:138