Blender V4.5
MOD_grease_pencil_build.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_array.hh"
10#include "BLI_sort.hh"
11
12#include "BLT_translation.hh"
13
14#include "BLO_read_write.hh"
15
16#include "DNA_defaults.h"
17#include "DNA_object_types.h"
18#include "DNA_scene_types.h"
19
21
22#include "BKE_curves.hh"
23#include "BKE_geometry_set.hh"
24#include "BKE_grease_pencil.hh"
25#include "BKE_lib_query.hh"
26#include "BKE_modifier.hh"
27
28#include "UI_interface.hh"
29#include "UI_resources.hh"
30
32#include "MOD_modifiertypes.hh"
33#include "MOD_ui_common.hh"
34
35#include "RNA_access.hh"
36#include "RNA_prototypes.hh"
37
38#include "GEO_reorder.hh"
39
40namespace blender {
41
51
52static void copy_data(const ModifierData *md, ModifierData *target, int flags)
53{
54 const auto *omd = reinterpret_cast<const GreasePencilBuildModifierData *>(md);
55 auto *tomd = reinterpret_cast<GreasePencilBuildModifierData *>(target);
56
58
59 BKE_modifier_copydata_generic(md, target, flags);
60 modifier::greasepencil::copy_influence_data(&omd->influence, &tomd->influence, flags);
61}
62
63static void free_data(ModifierData *md)
64{
65 auto *omd = reinterpret_cast<GreasePencilBuildModifierData *>(md);
67}
68
69static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
70{
71 auto *omd = reinterpret_cast<GreasePencilBuildModifierData *>(md);
72 modifier::greasepencil::foreach_influence_ID_link(&omd->influence, ob, walk, user_data);
73 walk(user_data, ob, (ID **)&omd->object, IDWALK_CB_NOP);
74}
75
77{
78 auto *mmd = reinterpret_cast<GreasePencilBuildModifierData *>(md);
79 if (mmd->object != nullptr) {
80 DEG_add_object_relation(ctx->node, mmd->object, DEG_OB_COMP_TRANSFORM, "Build Modifier");
81 }
82 DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Build Modifier");
83}
84
85static void blend_write(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md)
86{
87 const auto *mmd = reinterpret_cast<const GreasePencilBuildModifierData *>(md);
88
90 modifier::greasepencil::write_influence_data(writer, &mmd->influence);
91}
92
93static void blend_read(BlendDataReader *reader, ModifierData *md)
94{
95 auto *mmd = reinterpret_cast<GreasePencilBuildModifierData *>(md);
96
97 modifier::greasepencil::read_influence_data(reader, &mmd->influence);
98}
99
101 const IndexMask &selection,
102 const int time_alignment,
103 const int transition,
104 const float factor,
105 const bool clamp_points,
106 int &r_curves_num,
107 int &r_points_num)
108{
109 const int stroke_count = curves.curves_num();
110 const OffsetIndices<int> points_by_curve = curves.points_by_curve();
111 const VArray<bool> cyclic = curves.cyclic();
112
114 float max_length = 0;
115 for (const int stroke : curves.curves_range()) {
116 const bool stroke_cyclic = cyclic[stroke];
117 const float len = curves.evaluated_length_total_for_curve(stroke, stroke_cyclic);
118 max_length = math::max(max_length, len);
119 }
120
121 float factor_to_keep = transition == MOD_GREASE_PENCIL_BUILD_TRANSITION_GROW ? factor :
122 1.0f - factor;
123 if (clamp_points) {
124 r_curves_num = r_points_num = 0;
125 factor_to_keep = std::clamp(factor_to_keep, 0.0f, 1.0f);
126 }
127
128 auto get_stroke_factor = [&](const float factor, const int index) {
129 const bool stroke_cyclic = cyclic[index];
130 const float total_length = curves.evaluated_length_total_for_curve(index, stroke_cyclic);
131 if (total_length == 0) {
132 return factor > 0.5f ? 1.0f : 0.0f;
133 }
134 const float max_factor = max_length / total_length;
135 if (time_alignment == MOD_GREASE_PENCIL_BUILD_TIMEALIGN_START) {
136 if (clamp_points) {
137 return std::clamp(factor * max_factor, 0.0f, 1.0f);
138 }
139 return factor * max_factor;
140 }
141 if (time_alignment == MOD_GREASE_PENCIL_BUILD_TIMEALIGN_END) {
142 const float min_factor = max_factor - 1.0f;
143 const float use_factor = factor * max_factor;
144 if (clamp_points) {
145 return std::clamp(use_factor - min_factor, 0.0f, 1.0f);
146 }
147 return use_factor - min_factor;
148 }
149 return 0.0f;
150 };
151
152 Array<bool> select(stroke_count);
153 selection.to_bools(select.as_mutable_span());
154 Array<int> result(stroke_count);
155 for (const int curve : curves.curves_range()) {
156 const float local_factor = select[curve] ? get_stroke_factor(factor_to_keep, curve) : 1.0f;
157 const int num_points = points_by_curve[curve].size() * local_factor;
158 result[curve] = num_points;
159 if (clamp_points) {
160 r_points_num += num_points;
161 if (num_points > 0) {
162 r_curves_num++;
163 }
164 }
165 }
166 return result;
167}
168
170 bke::CurvesGeometry &curves,
171 const IndexMask &selection,
172 const int time_alignment,
173 const int transition,
174 const float factor,
175 const float factor_start,
176 const float factor_opacity,
177 const float factor_radii,
178 StringRefNull target_vgname)
179{
180 int dst_curves_num, dst_points_num;
181 const bool has_fade = factor_start != factor;
182 const Array<int> point_counts_to_keep = point_counts_to_keep_concurrent(
183 curves, selection, time_alignment, transition, factor, true, dst_curves_num, dst_points_num);
184 if (dst_curves_num == 0) {
185 return {};
186 }
187 const Array<int> starts_per_curve = has_fade ? point_counts_to_keep_concurrent(curves,
188 selection,
189 time_alignment,
190 transition,
191 factor_start,
192 false,
193 dst_curves_num,
194 dst_points_num) :
195 Array<int>(0);
196 const Array<int> ends_per_curve = has_fade ? point_counts_to_keep_concurrent(curves,
197 selection,
198 time_alignment,
199 transition,
200 factor,
201 false,
202 dst_curves_num,
203 dst_points_num) :
204 Array<int>(0);
205
206 const OffsetIndices<int> points_by_curve = curves.points_by_curve();
207 MutableSpan<float> opacities = drawing.opacities_for_write();
208 MutableSpan<float> radii = drawing.radii_for_write();
210 bke::SpanAttributeWriter<float> weights = attributes.lookup_for_write_span<float>(target_vgname);
211
212 const bool is_vanishing = transition == MOD_GREASE_PENCIL_BUILD_TRANSITION_VANISH;
213
214 bke::CurvesGeometry dst_curves(dst_points_num, dst_curves_num);
215 Array<int> dst_to_src_point(dst_points_num);
216 Array<int> dst_to_src_curve(dst_curves_num);
217 MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
218 dst_offsets[0] = 0;
219
220 int next_curve = 0;
221 int next_point = 0;
222 for (const int curve : curves.curves_range()) {
223 if (!point_counts_to_keep[curve]) {
224 continue;
225 }
226 const IndexRange points = points_by_curve[curve];
227 dst_offsets[next_curve] = point_counts_to_keep[curve];
228 const int curve_size = points.size();
229
230 auto get_fade_weight = [&](const int local_index) {
231 const float fade_range = std::abs(ends_per_curve[curve] - starts_per_curve[curve]);
232 if (is_vanishing) {
233 const float factor_from_start = local_index - curve_size + ends_per_curve[curve];
234 return 1.0f - std::clamp(factor_from_start / fade_range, 0.0f, 1.0f);
235 }
236 const float factor_from_start = local_index - starts_per_curve[curve];
237 return std::clamp(factor_from_start / fade_range, 0.0f, 1.0f);
238 };
239
240 const int extra_offset = is_vanishing ? points.size() - point_counts_to_keep[curve] : 0;
241 for (const int stroke_point : IndexRange(point_counts_to_keep[curve])) {
242 const int src_point_index = points.first() + extra_offset + stroke_point;
243 if (has_fade) {
244 const float fade_weight = get_fade_weight(extra_offset + stroke_point);
245 opacities[src_point_index] = opacities[src_point_index] *
246 (1.0f - fade_weight * factor_opacity);
247 radii[src_point_index] = radii[src_point_index] * (1.0f - fade_weight * factor_radii);
248 if (!weights.span.is_empty()) {
249 weights.span[src_point_index] = fade_weight;
250 }
251 }
252 dst_to_src_point[next_point] = src_point_index;
253 next_point++;
254 }
255 dst_to_src_curve[next_curve] = curve;
256 next_curve++;
257 }
258 weights.finish();
259
261
262 const bke::AttributeAccessor src_attributes = curves.attributes();
263 bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
264
265 gather_attributes(src_attributes,
268 {},
269 dst_to_src_point,
270 dst_attributes);
271 gather_attributes(src_attributes,
274 {},
275 dst_to_src_curve,
276 dst_attributes);
277
278 dst_curves.update_curve_types();
279
280 return dst_curves;
281}
282
284 const IndexMask &selection,
285 const int transition,
286 const float factor,
287 const bool clamp_points,
288 int &r_curves_num,
289 int &r_points_num)
290{
291 const int stroke_count = curves.curves_num();
292 const OffsetIndices<int> points_by_curve = curves.points_by_curve();
293
294 float factor_to_keep = transition == MOD_GREASE_PENCIL_BUILD_TRANSITION_GROW ? factor :
295 (1.0f - factor);
296 if (clamp_points) {
297 factor_to_keep = std::clamp(factor_to_keep, 0.0f, 1.0f);
298 }
299
300 const bool is_vanishing = transition == MOD_GREASE_PENCIL_BUILD_TRANSITION_VANISH;
301
302 int effective_points_num = offset_indices::sum_group_sizes(points_by_curve, selection);
303
304 const int untouched_points_num = points_by_curve.total_size() - effective_points_num;
305 effective_points_num *= factor_to_keep;
306 effective_points_num += untouched_points_num;
307
308 r_points_num = effective_points_num;
309 r_curves_num = 0;
310
311 Array<bool> select(stroke_count);
312 selection.to_bools(select.as_mutable_span());
313
314 int counted_points_num = 0;
315 for (const int i : curves.curves_range()) {
316 const int stroke = is_vanishing ? stroke_count - i - 1 : i;
317 if (select[stroke] && counted_points_num >= effective_points_num) {
318 continue;
319 }
320 counted_points_num += points_by_curve[stroke].size();
321 r_curves_num++;
322 }
323}
324
326 bke::CurvesGeometry &curves,
327 const IndexMask &selection,
328 const int transition,
329 const float factor,
330 const float factor_start,
331 const float factor_opacity,
332 const float factor_radii,
333 StringRefNull target_vgname)
334{
335 const bool has_fade = factor_start != factor;
336 int dst_curves_num, dst_points_num;
337 int start_points_num, end_points_num, dummy_curves_num;
339 curves, selection, transition, factor, true, dst_curves_num, dst_points_num);
340
341 if (dst_curves_num == 0) {
342 return {};
343 }
344
346 curves, selection, transition, factor_start, false, dummy_curves_num, start_points_num);
348 curves, selection, transition, factor, false, dummy_curves_num, end_points_num);
349
350 const OffsetIndices<int> points_by_curve = curves.points_by_curve();
351 MutableSpan<float> opacities = drawing.opacities_for_write();
352 MutableSpan<float> radii = drawing.radii_for_write();
354 bke::SpanAttributeWriter<float> weights = attributes.lookup_for_write_span<float>(target_vgname);
355
356 const bool is_vanishing = transition == MOD_GREASE_PENCIL_BUILD_TRANSITION_VANISH;
357
358 bke::CurvesGeometry dst_curves(dst_points_num, dst_curves_num);
359 MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
360 Array<int> dst_to_src_point(dst_points_num);
361 Array<int> dst_to_src_curve(dst_curves_num);
362
363 dst_offsets[0] = 0;
364
365 int next_curve = 1, next_point = 0;
366 IndexMaskMemory memory;
367 selection.complement(curves.curves_range(), memory).foreach_index([&](const int stroke) {
368 for (const int point : points_by_curve[stroke]) {
369 dst_to_src_point[next_point] = point;
370 next_point++;
371 }
372 dst_to_src_curve[next_curve - 1] = stroke;
373 dst_offsets[next_curve] = next_point;
374 next_curve++;
375 });
376
377 const int stroke_count = curves.curves_num();
378 bool done_scanning = false;
379 selection.foreach_index([&](const int i) {
380 const int stroke = is_vanishing ? stroke_count - i - 1 : i;
381 if (done_scanning || next_point >= dst_points_num) {
382 done_scanning = true;
383 return;
384 }
385
386 auto get_fade_weight = [&](const int next_point_count) {
387 return std::clamp(float(next_point_count - start_points_num) /
388 float(abs(end_points_num - start_points_num)),
389 0.0f,
390 1.0f);
391 };
392
393 const IndexRange points = points_by_curve[stroke];
394 for (const int point : points) {
395 const int local_index = point - points.first();
396 const int src_point_index = is_vanishing ? points.last() - local_index : point;
397 dst_to_src_point[next_point] = src_point_index;
398
399 if (has_fade) {
400 const float fade_weight = get_fade_weight(next_point);
401 opacities[src_point_index] = opacities[src_point_index] *
402 (1.0f - fade_weight * factor_opacity);
403 radii[src_point_index] = radii[src_point_index] * (1.0f - fade_weight * factor_radii);
404 if (!weights.span.is_empty()) {
405 weights.span[src_point_index] = fade_weight;
406 }
407 }
408
409 next_point++;
410 if (next_point >= dst_points_num) {
411 done_scanning = true;
412 break;
413 }
414 }
415 dst_offsets[next_curve] = next_point;
416 dst_to_src_curve[next_curve - 1] = i;
417 next_curve++;
418 });
419 weights.finish();
420
421 BLI_assert(next_curve == (dst_curves_num + 1));
422 BLI_assert(next_point == dst_points_num);
423
424 const bke::AttributeAccessor src_attributes = curves.attributes();
425 bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
426
427 gather_attributes(src_attributes,
430 {},
431 dst_to_src_point,
432 dst_attributes);
433 gather_attributes(src_attributes,
436 {},
437 dst_to_src_curve,
438 dst_attributes);
439
440 dst_curves.update_curve_types();
441
442 return dst_curves;
443}
444
446 const Span<bool> select,
447 const Object &object,
448 MutableSpan<bool> r_selection)
449{
450 const OffsetIndices<int> points_by_curve = curves.points_by_curve();
451 const Span<float3> positions = curves.positions();
452 const float3 center = object.object_to_world().location();
453
454 struct Pair {
455 float value;
456 int index;
457 bool selected;
458 };
459
460 Array<Pair> distances(curves.curves_num());
461 for (const int stroke : curves.curves_range()) {
462 const IndexRange points = points_by_curve[stroke];
463 const float3 p1 = positions[points.first()];
464 const float3 p2 = positions[points.last()];
465 distances[stroke].value = math::max(math::distance(p1, center), math::distance(p2, center));
466 distances[stroke].index = stroke;
467 distances[stroke].selected = select[stroke];
468 }
469
471 distances.begin(), distances.end(), [](Pair &a, Pair &b) { return a.value < b.value; });
472
473 Array<int> new_order(curves.curves_num());
474 for (const int i : curves.curves_range()) {
475 new_order[i] = distances[i].index;
476 r_selection[i] = distances[i].selected;
477 }
478
479 return geometry::reorder_curves_geometry(curves, new_order.as_span(), {});
480}
481
483 const float time_elapsed,
484 const float speed_fac,
485 const float max_gap,
486 const float frame_duration)
487{
488 const OffsetIndices<int> points_by_curve = curves.points_by_curve();
489 const bke::AttributeAccessor attributes = curves.attributes();
490 const VArray<float> init_times = *attributes.lookup_or_default<float>(
491 "init_time", bke::AttrDomain::Curve, 0.0f);
492 const VArray<float> delta_times = *attributes.lookup_or_default<float>(
493 "delta_time", bke::AttrDomain::Point, 0.0f);
494
495 Array<float> start_times(curves.curves_num());
496 start_times[0] = 0;
497 float accumulated_shift_delta_time = init_times[0];
498 for (const int curve : curves.curves_range().drop_front(1)) {
499 const float previous_start_time = start_times[curve - 1];
500 const float previous_delta_time = delta_times[points_by_curve[curve - 1].last()];
501 const float previous_end_time = previous_start_time + previous_delta_time;
502
503 const float shifted_start_time = init_times[curve] - accumulated_shift_delta_time;
504 const float gap_delta_time = math::min(math::abs(shifted_start_time - previous_end_time),
505 max_gap);
506
507 start_times[curve] = previous_end_time + gap_delta_time;
508 accumulated_shift_delta_time += math::max(shifted_start_time - start_times[curve], 0.0f);
509 }
510
511 /* Calculates the maximum time of this frame, which is the time between the beginning of the
512 * first stroke and the end of the last stroke. `start_times.last()` gives the starting time of
513 * the last stroke related to frame beginning, and `delta_time.last()` gives how long that stroke
514 * lasted. */
515 const float max_time = start_times.last() + delta_times.last();
516
517 /* If the time needed for building the frame is shorter than frame length, this gives the
518 * percentage of time it needs to be compared to original drawing time. `max_time/speed_fac`
519 * gives time after speed scaling, then divided by `frame_duration` gives the percentage. */
520 const float time_compress_factor = math::max(max_time / speed_fac / frame_duration, 1.0f);
521
522 /* Finally actual building limit is then scaled with speed factor and time compress factor. */
523 const float limit = time_elapsed * speed_fac * time_compress_factor;
524
525 for (const int curve : curves.curves_range()) {
526 const float start_time = start_times[curve];
527 for (const int point : points_by_curve[curve]) {
528 if (start_time + delta_times[point] >= limit) {
529 return math::clamp(float(point) / float(curves.points_num()), 0.0f, 1.0f);
530 }
531 }
532 }
533
534 return 1.0f;
535}
536
537static float get_build_factor(const GreasePencilBuildTimeMode time_mode,
538 const int current_frame,
539 const int start_frame,
540 const int frame_duration,
541 const int length,
542 const float percentage,
543 const bke::CurvesGeometry &curves,
544 const float scene_fps,
545 const float speed_fac,
546 const float max_gap,
547 const float fade)
548{
549 const float use_time = blender::math::round(
550 float(current_frame) / float(math::min(frame_duration, length)) * float(length));
551 const float build_factor_frames = math::clamp(
552 float(use_time - start_frame) / length, 0.0f, 1.0f) *
553 (1.0f + fade);
554 switch (time_mode) {
556 return build_factor_frames;
558 return percentage * (1.0f + fade);
560 /* The "drawing speed" is written as an attribute called 'delta_time' (for each point). If
561 * this attribute doesn't exist, we fall back to the "frames" mode. */
562 if (!curves.attributes().contains("delta_time")) {
563 return build_factor_frames;
564 }
565 return get_factor_from_draw_speed(curves,
566 float(current_frame) / scene_fps,
567 speed_fac,
568 max_gap,
569 float(frame_duration) / scene_fps) *
570 (1.0f + fade);
571 }
573 return 0.0f;
574}
575
577 const Object &ob,
579 const bke::greasepencil::Drawing *previous_drawing,
580 const int current_time,
581 const int frame_duration,
582 const float scene_fps)
583{
585 bke::CurvesGeometry &curves = drawing.strokes_for_write();
586
587 if (curves.is_empty()) {
588 return;
589 }
590
591 IndexMaskMemory memory;
593 &ob, curves, mmd.influence, memory);
594
595 /* Remove a count of #prev_strokes. */
596 if (mmd.mode == MOD_GREASE_PENCIL_BUILD_MODE_ADDITIVE && previous_drawing != nullptr) {
597 const bke::CurvesGeometry &prev_curves = previous_drawing->strokes();
598 const int prev_strokes = prev_curves.curves_num();
599 const int added_strokes = curves.curves_num() - prev_strokes;
600 if (added_strokes > 0) {
601 Array<bool> work_on_select(curves.curves_num());
602 selection.to_bools(work_on_select.as_mutable_span());
603 work_on_select.as_mutable_span().take_front(prev_strokes).fill(false);
604 selection = IndexMask::from_bools(work_on_select, memory);
605 }
606 }
607
608 if (mmd.object) {
609 const int curves_num = curves.curves_num();
610 Array<bool> select(curves_num), reordered_select(curves_num);
611 selection.to_bools(select);
612 curves = reorder_strokes(
613 curves, select.as_span(), *mmd.object, reordered_select.as_mutable_span());
614 selection = IndexMask::from_bools(reordered_select, memory);
615 }
616
617 const float fade_factor = ((mmd.flag & MOD_GREASE_PENCIL_BUILD_USE_FADING) != 0) ? mmd.fade_fac :
618 0.0f;
620 current_time,
621 mmd.start_delay,
622 frame_duration,
623 mmd.length,
624 mmd.percentage_fac,
625 curves,
626 scene_fps,
627 mmd.speed_fac,
628 mmd.speed_maxgap,
629 fade_factor);
630 float factor_start = factor - fade_factor;
632 std::swap(factor, factor_start);
633 }
634
635 const float use_time_alignment = mmd.transition != MOD_GREASE_PENCIL_BUILD_TRANSITION_GROW ?
636 !mmd.time_alignment :
637 mmd.time_alignment;
638 switch (mmd.mode) {
639 default:
641 curves = build_sequential(drawing,
642 curves,
643 selection,
644 mmd.transition,
645 factor,
646 factor_start,
649 mmd.target_vgname);
650 break;
652 curves = build_concurrent(drawing,
653 curves,
654 selection,
655 use_time_alignment,
656 mmd.transition,
657 factor,
658 factor_start,
661 mmd.target_vgname);
662 break;
664 curves = build_sequential(drawing,
665 curves,
666 selection,
667 mmd.transition,
668 factor,
669 factor_start,
672 mmd.target_vgname);
673 break;
674 }
675
676 drawing.tag_topology_changed();
677}
678
680 const ModifierEvalContext *ctx,
681 blender::bke::GeometrySet *geometry_set)
682{
683 const auto *mmd = reinterpret_cast<GreasePencilBuildModifierData *>(md);
684
685 if (!geometry_set->has_grease_pencil()) {
686 return;
687 }
688
689 GreasePencil &grease_pencil = *geometry_set->get_grease_pencil_for_write();
690 const int eval_frame = grease_pencil.runtime->eval_frame;
691
692 IndexMaskMemory mask_memory;
694 grease_pencil, mmd->influence, mask_memory);
696 modifier::greasepencil::get_drawing_infos_by_layer(grease_pencil, layer_mask, eval_frame);
697
699 if (eval_frame < mmd->start_frame || eval_frame > mmd->end_frame) {
700 return;
701 }
702 }
703
704 const Scene &scene = *DEG_get_evaluated_scene(ctx->depsgraph);
705 const float scene_fps = float(scene.r.frs_sec) / scene.r.frs_sec_base;
706 const Span<const bke::greasepencil::Layer *> layers = grease_pencil.layers();
707
709 drawing_infos, [&](modifier::greasepencil::LayerDrawingInfo drawing_info) {
710 const bke::greasepencil::Layer &layer = *layers[drawing_info.layer_index];
711
712 /* This will always return a valid start frame because we're iterating over the valid
713 * drawings on `eval_frame`. Each drawing will have a start frame. */
714 const int start_frame = *layer.start_frame_at(eval_frame);
715 BLI_assert(start_frame <= eval_frame);
716
717 const bke::greasepencil::Drawing *prev_drawing = grease_pencil.get_drawing_at(
718 layer, start_frame - 1);
719
720 const int relative_start_frame = eval_frame - start_frame;
721
722 const int frame_index = layer.sorted_keys_index_at(eval_frame);
723 BLI_assert(frame_index != -1);
724
725 int frame_duration = INT_MAX;
726 if (frame_index != layer.sorted_keys().index_range().last()) {
727 const int next_frame = layer.sorted_keys()[frame_index + 1];
728 frame_duration = math::distance(start_frame, next_frame);
729 }
730
731 build_drawing(*mmd,
732 *ctx->object,
733 *drawing_info.drawing,
734 prev_drawing,
735 relative_start_frame,
736 frame_duration,
737 scene_fps);
738 });
739}
740
741static void panel_draw(const bContext *C, Panel *panel)
742{
743 uiLayout *layout = panel->layout;
744
745 PointerRNA ob_ptr;
747
750
751 uiLayoutSetPropSep(layout, true);
752
753 /* First: Build mode and build settings. */
754 layout->prop(ptr, "mode", UI_ITEM_NONE, std::nullopt, ICON_NONE);
756 layout->prop(ptr, "transition", UI_ITEM_NONE, std::nullopt, ICON_NONE);
757 }
759 /* Concurrent mode doesn't support MOD_GREASE_PENCIL_BUILD_TIMEMODE_DRAWSPEED, so unset it. */
763 }
764 layout->prop(ptr, "transition", UI_ITEM_NONE, std::nullopt, ICON_NONE);
765 }
766 layout->separator();
767
768 /* Second: Time mode and time settings. */
769
770 layout->prop(ptr, "time_mode", UI_ITEM_NONE, std::nullopt, ICON_NONE);
772 layout->prop(ptr, "concurrent_time_alignment", UI_ITEM_NONE, std::nullopt, ICON_NONE);
773 }
774 switch (time_mode) {
776 layout->prop(ptr, "speed_factor", UI_ITEM_NONE, std::nullopt, ICON_NONE);
777 layout->prop(ptr, "speed_maxgap", UI_ITEM_NONE, std::nullopt, ICON_NONE);
778 break;
780 layout->prop(ptr, "length", UI_ITEM_NONE, IFACE_("Frames"), ICON_NONE);
782 layout->prop(ptr, "start_delay", UI_ITEM_NONE, std::nullopt, ICON_NONE);
783 }
784 break;
786 layout->prop(ptr, "percentage_factor", UI_ITEM_NONE, std::nullopt, ICON_NONE);
787 break;
788 default:
789 break;
790 }
791 layout->separator();
792 layout->prop(ptr, "object", UI_ITEM_NONE, std::nullopt, ICON_NONE);
793 PanelLayout restrict_frame_range_layout = layout->panel_prop_with_bool_header(
794 C,
795 ptr,
796 "open_frame_range_panel",
797 ptr,
798 "use_restrict_frame_range",
799 IFACE_("Effective Range"));
800 if (uiLayout *panel = restrict_frame_range_layout.body) {
801 const bool active = RNA_boolean_get(ptr, "use_restrict_frame_range");
802 uiLayout *col = &panel->column(false);
804 col->prop(ptr, "frame_start", UI_ITEM_NONE, IFACE_("Start"), ICON_NONE);
805 col->prop(ptr, "frame_end", UI_ITEM_NONE, IFACE_("End"), ICON_NONE);
806 }
807 PanelLayout fading_layout = layout->panel_prop_with_bool_header(
808 C, ptr, "open_fading_panel", ptr, "use_fading", IFACE_("Fading"));
809 if (uiLayout *panel = fading_layout.body) {
810 const bool active = RNA_boolean_get(ptr, "use_fading");
811 uiLayout *col = &panel->column(false);
813
814 col->prop(ptr, "fade_factor", UI_ITEM_NONE, IFACE_("Factor"), ICON_NONE);
815
816 uiLayout *subcol = &col->column(true);
817 subcol->prop(ptr, "fade_thickness_strength", UI_ITEM_NONE, IFACE_("Thickness"), ICON_NONE);
818 subcol->prop(ptr, "fade_opacity_strength", UI_ITEM_NONE, IFACE_("Opacity"), ICON_NONE);
819
821 ptr,
822 "target_vertex_group",
823 &ob_ptr,
824 "vertex_groups",
825 IFACE_("Weight Output"),
826 ICON_NONE);
827 }
828
829 if (uiLayout *influence_panel = layout->panel_prop(
830 C, ptr, "open_influence_panel", IFACE_("Influence")))
831 {
834 }
835
837}
838
843
844} // namespace blender
845
847 /*idname*/ "GreasePencilBuildModifier",
848 /*name*/ N_("Build"),
849 /*struct_name*/ "GreasePencilBuildModifierData",
850 /*struct_size*/ sizeof(GreasePencilBuildModifierData),
851 /*srna*/ &RNA_GreasePencilBuildModifier,
853 /*flags*/
856 /*icon*/ ICON_MOD_LENGTH,
857
858 /*copy_data*/ blender::copy_data,
859
860 /*deform_verts*/ nullptr,
861 /*deform_matrices*/ nullptr,
862 /*deform_verts_EM*/ nullptr,
863 /*deform_matrices_EM*/ nullptr,
864 /*modify_mesh*/ nullptr,
865 /*modify_geometry_set*/ blender::modify_geometry_set,
866
867 /*init_data*/ blender::init_data,
868 /*required_data_mask*/ nullptr,
869 /*free_data*/ blender::free_data,
870 /*is_disabled*/ nullptr,
871 /*update_depsgraph*/ blender::update_depsgraph,
872 /*depends_on_time*/ nullptr,
873 /*depends_on_normals*/ nullptr,
874 /*foreach_ID_link*/ blender::foreach_ID_link,
875 /*foreach_tex_link*/ nullptr,
876 /*free_runtime_data*/ nullptr,
877 /*panel_register*/ blender::panel_register,
878 /*blend_write*/ blender::blend_write,
879 /*blend_read*/ blender::blend_read,
880};
Low-level operations for curves.
Low-level operations for grease pencil.
@ IDWALK_CB_NOP
void(*)(void *user_data, Object *ob, ID **idpoin, LibraryForeachIDCallbackFlag cb_flag) IDWalkFunc
void BKE_modifier_copydata_generic(const ModifierData *md, ModifierData *md_dst, int flag)
@ eModifierTypeFlag_AcceptsGreasePencil
@ eModifierTypeFlag_EnableInEditmode
@ eModifierTypeFlag_SupportsEditmode
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define BLO_write_struct(writer, struct_name, data_ptr)
#define IFACE_(msgid)
void DEG_add_object_relation(DepsNodeHandle *node_handle, Object *object, eDepsObjectComponentType component, const char *description)
@ DEG_OB_COMP_TRANSFORM
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
#define DNA_struct_default_get(struct_name)
GreasePencilBuildTimeMode
@ MOD_GREASE_PENCIL_BUILD_TIMEMODE_PERCENTAGE
@ MOD_GREASE_PENCIL_BUILD_TIMEMODE_DRAWSPEED
@ MOD_GREASE_PENCIL_BUILD_TIMEMODE_FRAMES
@ MOD_GREASE_PENCIL_BUILD_TIMEALIGN_START
@ MOD_GREASE_PENCIL_BUILD_TIMEALIGN_END
GreasePencilBuildMode
@ MOD_GREASE_PENCIL_BUILD_MODE_SEQUENTIAL
@ MOD_GREASE_PENCIL_BUILD_MODE_ADDITIVE
@ MOD_GREASE_PENCIL_BUILD_MODE_CONCURRENT
@ MOD_GREASE_PENCIL_BUILD_RESTRICT_TIME
@ MOD_GREASE_PENCIL_BUILD_USE_FADING
@ eModifierType_GreasePencilBuild
@ MOD_GREASE_PENCIL_BUILD_TRANSITION_VANISH
@ MOD_GREASE_PENCIL_BUILD_TRANSITION_GROW
Object is a sort of wrapper for general info.
ModifierTypeInfo modifierType_GreasePencilBuild
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_error_message_draw(uiLayout *layout, PointerRNA *ptr)
#define C
Definition RandGen.cpp:29
void uiLayoutSetActive(uiLayout *layout, bool active)
void uiItemPointerR(uiLayout *layout, PointerRNA *ptr, blender::StringRefNull propname, PointerRNA *searchptr, blender::StringRefNull searchpropname, std::optional< blender::StringRefNull > name, int icon)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
Span< T > as_span() const
Definition BLI_array.hh:232
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:237
const T * end() const
Definition BLI_array.hh:314
const T * begin() const
Definition BLI_array.hh:310
static IndexMask from_bools(Span< bool > bools, IndexMaskMemory &memory)
constexpr int64_t first() const
constexpr int64_t last(const int64_t n=0) const
constexpr int64_t size() const
constexpr IndexRange drop_front(int64_t n) const
T last(const int64_t n=0) const
bool contains(StringRef attribute_id) const
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const void *default_value=nullptr) const
OffsetIndices< int > points_by_curve() const
IndexRange curves_range() const
MutableAttributeAccessor attributes_for_write()
Span< float3 > positions() const
AttributeAccessor attributes() const
float evaluated_length_total_for_curve(int curve_index, bool cyclic) const
MutableSpan< int > offsets_for_write()
VArray< bool > cyclic() const
GSpanAttributeWriter lookup_for_write_span(StringRef attribute_id)
MutableSpan< float > opacities_for_write()
MutableSpan< float > radii_for_write()
bke::CurvesGeometry & strokes_for_write()
const bke::CurvesGeometry & strokes() const
int sorted_keys_index_at(int frame_number) const
std::optional< int > start_frame_at(int frame_number) const
Span< FramesMapKeyT > sorted_keys() const
IndexMask complement(const IndexMask &universe, IndexMaskMemory &memory) const
void to_bools(MutableSpan< bool > r_bools) const
void foreach_index(Fn &&fn) const
uint col
#define active
#define abs
#define select(A, B, C)
float length(VecOp< float, D >) RET
bke::CurvesGeometry reorder_curves_geometry(const bke::CurvesGeometry &src_curves, Span< int > old_by_new_map, const bke::AttributeFilter &attribute_filter)
Definition reorder.cc:348
T clamp(const T &a, const T &min, const T &max)
T distance(const T &a, const T &b)
T min(const T &a, const T &b)
T max(const T &a, const T &b)
T abs(const T &a)
T round(const T &a)
void read_influence_data(BlendDataReader *reader, GreasePencilModifierInfluenceData *influence_data)
void init_influence_data(GreasePencilModifierInfluenceData *influence_data, const bool has_custom_curve)
Vector< LayerDrawingInfo > get_drawing_infos_by_layer(GreasePencil &grease_pencil, const IndexMask &layer_mask, const int frame)
static IndexMask get_filtered_stroke_mask(const Object *ob, const bke::CurvesGeometry &curves, const Material *material_filter, const std::optional< int > material_pass_filter, const bool material_filter_invert, const bool material_pass_filter_invert, IndexMaskMemory &memory)
void write_influence_data(BlendWriter *writer, const GreasePencilModifierInfluenceData *influence_data)
static IndexMask get_filtered_layer_mask(const GreasePencil &grease_pencil, const std::optional< StringRef > tree_node_name_filter, const std::optional< int > layer_pass_filter, const bool layer_filter_invert, const bool layer_pass_filter_invert, IndexMaskMemory &memory)
void draw_material_filter_settings(const bContext *, uiLayout *layout, PointerRNA *ptr)
void draw_layer_filter_settings(const bContext *, uiLayout *layout, PointerRNA *ptr)
void free_influence_data(GreasePencilModifierInfluenceData *influence_data)
void foreach_influence_ID_link(GreasePencilModifierInfluenceData *influence_data, Object *ob, IDWalkFunc walk, void *user_data)
void copy_influence_data(const GreasePencilModifierInfluenceData *influence_data_src, GreasePencilModifierInfluenceData *influence_data_dst, const int)
void ensure_no_bezier_curves(Drawing &drawing)
OffsetIndices< int > accumulate_counts_to_offsets(MutableSpan< int > counts_to_offsets, int start_offset=0)
int sum_group_sizes(OffsetIndices< int > offsets, const IndexMask &mask)
void parallel_for_each(Range &&range, const Function &function)
Definition BLI_task.hh:56
static Array< int > point_counts_to_keep_concurrent(const bke::CurvesGeometry &curves, const IndexMask &selection, const int time_alignment, const int transition, const float factor, const bool clamp_points, int &r_curves_num, int &r_points_num)
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
static void blend_write(BlendWriter *writer, const ID *, const ModifierData *md)
static bke::CurvesGeometry build_sequential(bke::greasepencil::Drawing &drawing, bke::CurvesGeometry &curves, const IndexMask &selection, const int transition, const float factor, const float factor_start, const float factor_opacity, const float factor_radii, StringRefNull target_vgname)
static void init_data(ModifierData *md)
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
static void points_info_sequential(const bke::CurvesGeometry &curves, const IndexMask &selection, const int transition, const float factor, const bool clamp_points, int &r_curves_num, int &r_points_num)
static void panel_draw(const bContext *C, Panel *panel)
static float get_factor_from_draw_speed(const bke::CurvesGeometry &curves, const float time_elapsed, const float speed_fac, const float max_gap, const float frame_duration)
static float get_build_factor(const GreasePencilBuildTimeMode time_mode, const int current_frame, const int start_frame, const int frame_duration, const int length, const float percentage, const bke::CurvesGeometry &curves, const float scene_fps, const float speed_fac, const float max_gap, const float fade)
static void modify_geometry_set(ModifierData *md, const ModifierEvalContext *ctx, bke::GeometrySet *geometry_set)
void parallel_sort(RandomAccessIterator begin, RandomAccessIterator end)
Definition BLI_sort.hh:23
static bke::CurvesGeometry reorder_strokes(const bke::CurvesGeometry &curves, const Span< bool > select, const Object &object, MutableSpan< bool > r_selection)
static void free_data(ModifierData *md)
static void build_drawing(const GreasePencilBuildModifierData &mmd, const Object &ob, bke::greasepencil::Drawing &drawing, const bke::greasepencil::Drawing *previous_drawing, const int current_time, const int frame_duration, const float scene_fps)
static void panel_register(ARegionType *region_type)
static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
VecBase< float, 3 > float3
static void blend_read(BlendDataReader *reader, ModifierData *md)
static bke::CurvesGeometry build_concurrent(bke::greasepencil::Drawing &drawing, bke::CurvesGeometry &curves, const IndexMask &selection, const int time_alignment, const int transition, const float factor, const float factor_start, const float factor_opacity, const float factor_radii, StringRefNull target_vgname)
CCL_NAMESPACE_BEGIN ccl_device float fade(const float t)
Definition noise.h:18
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
int RNA_enum_get(PointerRNA *ptr, const char *name)
GreasePencilModifierInfluenceData influence
GreasePencilRuntimeHandle * runtime
Definition DNA_ID.h:404
struct uiLayout * layout
struct RenderData r
GreasePencil * get_grease_pencil_for_write()
PanelLayout panel_prop_with_bool_header(const bContext *C, PointerRNA *open_prop_owner, blender::StringRefNull open_prop_name, PointerRNA *bool_prop_owner, blender::StringRefNull bool_prop_name, std::optional< blender::StringRefNull > label)
PanelLayout panel_prop(const bContext *C, PointerRNA *open_prop_owner, blender::StringRefNull open_prop_name)
void separator(float factor=1.0f, LayoutSeparatorType type=LayoutSeparatorType::Auto)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
i
Definition text_draw.cc:230
uint len
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4226