Blender V4.3
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_hash.h"
11#include "BLI_rand.h"
12#include "BLI_sort.hh"
13#include "BLI_task.h"
14
15#include "BLT_translation.hh"
16
17#include "BLO_read_write.hh"
18
19#include "DNA_defaults.h"
21#include "DNA_object_types.h"
22#include "DNA_scene_types.h"
23
25
26#include "BKE_curves.hh"
27#include "BKE_geometry_set.hh"
28#include "BKE_grease_pencil.hh"
29#include "BKE_lib_query.hh"
30#include "BKE_modifier.hh"
31
32#include "UI_interface.hh"
33#include "UI_resources.hh"
34
36#include "MOD_modifiertypes.hh"
37#include "MOD_ui_common.hh"
38
39#include "RNA_access.hh"
40#include "RNA_prototypes.hh"
41
42#include "GEO_reorder.hh"
43
44namespace blender {
45
55
56static void copy_data(const ModifierData *md, ModifierData *target, int flags)
57{
58 const auto *omd = reinterpret_cast<const GreasePencilBuildModifierData *>(md);
59 auto *tomd = reinterpret_cast<GreasePencilBuildModifierData *>(target);
60
62
63 BKE_modifier_copydata_generic(md, target, flags);
64 modifier::greasepencil::copy_influence_data(&omd->influence, &tomd->influence, flags);
65}
66
67static void free_data(ModifierData *md)
68{
69 auto *omd = reinterpret_cast<GreasePencilBuildModifierData *>(md);
71}
72
73static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
74{
75 auto *omd = reinterpret_cast<GreasePencilBuildModifierData *>(md);
76 modifier::greasepencil::foreach_influence_ID_link(&omd->influence, ob, walk, user_data);
77 walk(user_data, ob, (ID **)&omd->object, IDWALK_CB_NOP);
78}
79
81{
82 auto *mmd = reinterpret_cast<GreasePencilBuildModifierData *>(md);
83 if (mmd->object != nullptr) {
84 DEG_add_object_relation(ctx->node, mmd->object, DEG_OB_COMP_TRANSFORM, "Build Modifier");
85 }
86 DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Build Modifier");
87}
88
89static void blend_write(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md)
90{
91 const auto *mmd = reinterpret_cast<const GreasePencilBuildModifierData *>(md);
92
94 modifier::greasepencil::write_influence_data(writer, &mmd->influence);
95}
96
97static void blend_read(BlendDataReader *reader, ModifierData *md)
98{
99 auto *mmd = reinterpret_cast<GreasePencilBuildModifierData *>(md);
100
101 modifier::greasepencil::read_influence_data(reader, &mmd->influence);
102}
103
105 const IndexMask &selection,
106 const int time_alignment,
107 const int transition,
108 const float factor,
109 const bool clamp_points,
110 int &r_curves_num,
111 int &r_points_num)
112{
113 const int stroke_count = curves.curves_num();
114 const OffsetIndices<int> points_by_curve = curves.points_by_curve();
115 const VArray<bool> cyclic = curves.cyclic();
116
118 float max_length = 0;
119 for (const int stroke : curves.curves_range()) {
120 const bool stroke_cyclic = cyclic[stroke];
121 const float len = curves.evaluated_length_total_for_curve(stroke, stroke_cyclic);
122 max_length = math::max(max_length, len);
123 }
124
125 float factor_to_keep = transition == MOD_GREASE_PENCIL_BUILD_TRANSITION_GROW ? factor :
126 1.0f - factor;
127 if (clamp_points) {
128 r_curves_num = r_points_num = 0;
129 factor_to_keep = std::clamp(factor_to_keep, 0.0f, 1.0f);
130 }
131
132 auto get_stroke_factor = [&](const float factor, const int index) {
133 const bool stroke_cyclic = cyclic[index];
134 const float max_factor = max_length /
135 curves.evaluated_length_total_for_curve(index, stroke_cyclic);
136 if (time_alignment == MOD_GREASE_PENCIL_BUILD_TIMEALIGN_START) {
137 if (clamp_points) {
138 return std::clamp(factor * max_factor, 0.0f, 1.0f);
139 }
140 return factor * max_factor;
141 }
142 if (time_alignment == MOD_GREASE_PENCIL_BUILD_TIMEALIGN_END) {
143 const float min_factor = max_factor - 1.0f;
144 const float use_factor = factor * max_factor;
145 if (clamp_points) {
146 return std::clamp(use_factor - min_factor, 0.0f, 1.0f);
147 }
148 return use_factor - min_factor;
149 }
150 return 0.0f;
151 };
152
153 Array<bool> select(stroke_count);
154 selection.to_bools(select.as_mutable_span());
155 Array<int> result(stroke_count);
156 for (const int curve : curves.curves_range()) {
157 const float local_factor = select[curve] ? get_stroke_factor(factor_to_keep, curve) : 1.0f;
158 const int num_points = points_by_curve[curve].size() * local_factor;
159 result[curve] = num_points;
160 if (clamp_points) {
161 r_points_num += num_points;
162 if (num_points > 0) {
163 r_curves_num++;
164 }
165 }
166 }
167 return result;
168}
169
171 bke::CurvesGeometry &curves,
172 const IndexMask &selection,
173 const int time_alignment,
174 const int transition,
175 const float factor,
176 const float factor_start,
177 const float factor_opacity,
178 const float factor_radii,
179 StringRefNull target_vgname)
180{
181 int dst_curves_num, dst_points_num;
182 const bool has_fade = factor_start != factor;
183 const Array<int> point_counts_to_keep = point_counts_to_keep_concurrent(
184 curves, selection, time_alignment, transition, factor, true, dst_curves_num, dst_points_num);
185 if (dst_curves_num == 0) {
186 return {};
187 }
188 const Array<int> starts_per_curve = has_fade ? point_counts_to_keep_concurrent(curves,
189 selection,
190 time_alignment,
191 transition,
192 factor_start,
193 false,
194 dst_curves_num,
195 dst_points_num) :
196 Array<int>(0);
197 const Array<int> ends_per_curve = has_fade ? point_counts_to_keep_concurrent(curves,
198 selection,
199 time_alignment,
200 transition,
201 factor,
202 false,
203 dst_curves_num,
204 dst_points_num) :
205 Array<int>(0);
206
207 const OffsetIndices<int> points_by_curve = curves.points_by_curve();
208 MutableSpan<float> opacities = drawing.opacities_for_write();
209 MutableSpan<float> radii = drawing.radii_for_write();
211 bke::SpanAttributeWriter<float> weights = attributes.lookup_for_write_span<float>(target_vgname);
212
213 const bool is_vanishing = transition == MOD_GREASE_PENCIL_BUILD_TRANSITION_VANISH;
214
215 bke::CurvesGeometry dst_curves(dst_points_num, dst_curves_num);
216 Array<int> dst_to_src_point(dst_points_num);
217 Array<int> dst_to_src_curve(dst_curves_num);
218 MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
219 dst_offsets[0] = 0;
220
221 int next_curve = 0;
222 int next_point = 0;
223 for (const int curve : curves.curves_range()) {
224 if (!point_counts_to_keep[curve]) {
225 continue;
226 }
227 const IndexRange points = points_by_curve[curve];
228 dst_offsets[next_curve] = point_counts_to_keep[curve];
229 const int curve_size = points.size();
230
231 auto get_fade_weight = [&](const int local_index) {
232 const float fade_range = std::abs(ends_per_curve[curve] - starts_per_curve[curve]);
233 if (is_vanishing) {
234 const float factor_from_start = local_index - curve_size + ends_per_curve[curve];
235 return 1.0f - std::clamp(factor_from_start / fade_range, 0.0f, 1.0f);
236 }
237 const float factor_from_start = local_index - starts_per_curve[curve];
238 return std::clamp(factor_from_start / fade_range, 0.0f, 1.0f);
239 };
240
241 const int extra_offset = is_vanishing ? points.size() - point_counts_to_keep[curve] : 0;
242 for (const int stroke_point : IndexRange(point_counts_to_keep[curve])) {
243 const int src_point_index = points.first() + extra_offset + stroke_point;
244 if (has_fade) {
245 const float fade_weight = get_fade_weight(extra_offset + stroke_point);
246 opacities[src_point_index] = opacities[src_point_index] *
247 (1.0f - fade_weight * factor_opacity);
248 radii[src_point_index] = radii[src_point_index] * (1.0f - fade_weight * factor_radii);
249 if (!weights.span.is_empty()) {
250 weights.span[src_point_index] = fade_weight;
251 }
252 }
253 dst_to_src_point[next_point] = src_point_index;
254 next_point++;
255 }
256 dst_to_src_curve[next_curve] = curve;
257 next_curve++;
258 }
259 weights.finish();
260
262
263 const bke::AttributeAccessor src_attributes = curves.attributes();
264 bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
265
266 gather_attributes(src_attributes,
269 {},
270 dst_to_src_point,
271 dst_attributes);
272 gather_attributes(src_attributes,
275 {},
276 dst_to_src_curve,
277 dst_attributes);
278
279 dst_curves.update_curve_types();
280
281 return dst_curves;
282}
283
285 const IndexMask &selection,
286 const int transition,
287 const float factor,
288 const bool clamp_points,
289 int &r_curves_num,
290 int &r_points_num)
291{
292 const int stroke_count = curves.curves_num();
293 const OffsetIndices<int> points_by_curve = curves.points_by_curve();
294
295 float factor_to_keep = transition == MOD_GREASE_PENCIL_BUILD_TRANSITION_GROW ? factor :
296 (1.0f - factor);
297 if (clamp_points) {
298 factor_to_keep = std::clamp(factor_to_keep, 0.0f, 1.0f);
299 }
300
301 const bool is_vanishing = transition == MOD_GREASE_PENCIL_BUILD_TRANSITION_VANISH;
302
303 int effective_points_num = offset_indices::sum_group_sizes(points_by_curve, selection);
304
305 const int untouched_points_num = points_by_curve.total_size() - effective_points_num;
306 effective_points_num *= factor_to_keep;
307 effective_points_num += untouched_points_num;
308
309 r_points_num = effective_points_num;
310 r_curves_num = 0;
311
312 Array<bool> select(stroke_count);
313 selection.to_bools(select.as_mutable_span());
314
315 int counted_points_num = 0;
316 for (const int i : curves.curves_range()) {
317 const int stroke = is_vanishing ? stroke_count - i - 1 : i;
318 if (select[stroke] && counted_points_num >= effective_points_num) {
319 continue;
320 }
321 counted_points_num += points_by_curve[stroke].size();
322 r_curves_num++;
323 }
324}
325
327 bke::CurvesGeometry &curves,
328 const IndexMask &selection,
329 const int transition,
330 const float factor,
331 const float factor_start,
332 const float factor_opacity,
333 const float factor_radii,
334 StringRefNull target_vgname)
335{
336 const bool has_fade = factor_start != factor;
337 int dst_curves_num, dst_points_num;
338 int start_points_num, end_points_num, dummy_curves_num;
340 curves, selection, transition, factor, true, dst_curves_num, dst_points_num);
341
342 if (dst_curves_num == 0) {
343 return {};
344 }
345
347 curves, selection, transition, factor_start, false, dummy_curves_num, start_points_num);
349 curves, selection, transition, factor, false, dummy_curves_num, end_points_num);
350
351 const OffsetIndices<int> points_by_curve = curves.points_by_curve();
352 MutableSpan<float> opacities = drawing.opacities_for_write();
353 MutableSpan<float> radii = drawing.radii_for_write();
355 bke::SpanAttributeWriter<float> weights = attributes.lookup_for_write_span<float>(target_vgname);
356
357 const bool is_vanishing = transition == MOD_GREASE_PENCIL_BUILD_TRANSITION_VANISH;
358
359 bke::CurvesGeometry dst_curves(dst_points_num, dst_curves_num);
360 MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
361 Array<int> dst_to_src_point(dst_points_num);
362 Array<int> dst_to_src_curve(dst_curves_num);
363
364 dst_offsets[0] = 0;
365
366 int next_curve = 1, next_point = 0;
367 IndexMaskMemory memory;
368 selection.complement(curves.curves_range(), memory).foreach_index([&](const int stroke) {
369 for (const int point : points_by_curve[stroke]) {
370 dst_to_src_point[next_point] = point;
371 next_point++;
372 }
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(shifted_start_time - previous_end_time, max_gap);
505
506 start_times[curve] = previous_end_time + gap_delta_time;
507 accumulated_shift_delta_time += math::max(shifted_start_time - start_times[curve], 0.0f);
508 }
509
510 /* Caclulates the maximum time of this frame, which is the time between the beginning of the
511 * first stroke and the end of the last stroke. `start_times.last()` gives the starting time of
512 * the last stroke related to frame beginning, and `delta_time.last()` gives how long that stroke
513 * lasted. */
514 const float max_time = start_times.last() + delta_times.last();
515
516 /* If the time needed for building the frame is shorter than frame length, this gives the
517 * percentage of time it needs to be compared to original drawing time. `max_time/speed_fac`
518 * gives time after speed scaling, then divided by `frame_duration` gives the percentage. */
519 const float time_compress_factor = math::max(max_time / speed_fac / frame_duration, 1.0f);
520
521 /* Finally actual building limit is then scaled with speed factor and time compress factor. */
522 const float limit = time_elapsed * speed_fac * time_compress_factor;
523
524 for (const int curve : curves.curves_range()) {
525 const float start_time = start_times[curve];
526 for (const int point : points_by_curve[curve]) {
527 if (start_time + delta_times[point] >= limit) {
528 return math::clamp(float(point) / float(curves.points_num()), 0.0f, 1.0f);
529 }
530 }
531 }
532
533 return 1.0f;
534}
535
536static float get_build_factor(const GreasePencilBuildTimeMode time_mode,
537 const int current_frame,
538 const int start_frame,
539 const int frame_duration,
540 const int length,
541 const float percentage,
542 const bke::CurvesGeometry &curves,
543 const float scene_fps,
544 const float speed_fac,
545 const float max_gap,
546 const float fade)
547{
548 const float use_time = blender::math::round(
549 float(current_frame) / float(math::min(frame_duration, length)) * float(length));
550 const float build_factor_frames = math::clamp(
551 float(use_time - start_frame) / length, 0.0f, 1.0f) *
552 (1.0f + fade);
553 switch (time_mode) {
555 return build_factor_frames;
557 return percentage * (1.0f + fade);
559 /* The "drawing speed" is written as an attribute called 'delta_time' (for each point). If
560 * this attribute doesn't exist, we fallback to the "frames" mode. */
561 if (!curves.attributes().contains("delta_time")) {
562 return build_factor_frames;
563 }
564 return get_factor_from_draw_speed(curves,
565 float(current_frame) / scene_fps,
566 speed_fac,
567 max_gap,
568 float(frame_duration) / scene_fps) *
569 (1.0f + fade);
570 }
572 return 0.0f;
573}
574
576 const Object &ob,
578 const bke::greasepencil::Drawing *previous_drawing,
579 const int current_time,
580 const int frame_duration,
581 const float scene_fps)
582{
584 bke::CurvesGeometry &curves = drawing.strokes_for_write();
585
586 if (curves.points_num() == 0) {
587 return;
588 }
589
590 IndexMaskMemory memory;
592 &ob, curves, mmd.influence, memory);
593
594 /* Remove a count of #prev_strokes. */
595 if (mmd.mode == MOD_GREASE_PENCIL_BUILD_MODE_ADDITIVE && previous_drawing != nullptr) {
596 const bke::CurvesGeometry &prev_curves = previous_drawing->strokes();
597 const int prev_strokes = prev_curves.curves_num();
598 const int added_strokes = curves.curves_num() - prev_strokes;
599 if (added_strokes > 0) {
600 Array<bool> work_on_select(curves.curves_num());
601 selection.to_bools(work_on_select.as_mutable_span());
602 work_on_select.as_mutable_span().take_front(prev_strokes).fill(false);
603 selection = IndexMask::from_bools(work_on_select, memory);
604 }
605 }
606
607 if (mmd.object) {
608 const int curves_num = curves.curves_num();
609 Array<bool> select(curves_num), reordered_select(curves_num);
610 selection.to_bools(select);
611 curves = reorder_strokes(
612 curves, select.as_span(), *mmd.object, reordered_select.as_mutable_span());
613 selection = IndexMask::from_bools(reordered_select, memory);
614 }
615
616 const float fade_factor = ((mmd.flag & MOD_GREASE_PENCIL_BUILD_USE_FADING) != 0) ? mmd.fade_fac :
617 0.0f;
619 current_time,
620 mmd.start_delay,
621 frame_duration,
622 mmd.length,
623 mmd.percentage_fac,
624 curves,
625 scene_fps,
626 mmd.speed_fac,
627 mmd.speed_maxgap,
628 fade_factor);
629 float factor_start = factor - fade_factor;
631 std::swap(factor, factor_start);
632 }
633
634 const float use_time_alignment = mmd.transition != MOD_GREASE_PENCIL_BUILD_TRANSITION_GROW ?
635 !mmd.time_alignment :
636 mmd.time_alignment;
637 switch (mmd.mode) {
638 default:
640 curves = build_sequential(drawing,
641 curves,
642 selection,
643 mmd.transition,
644 factor,
645 factor_start,
648 mmd.target_vgname);
649 break;
651 curves = build_concurrent(drawing,
652 curves,
653 selection,
654 use_time_alignment,
655 mmd.transition,
656 factor,
657 factor_start,
660 mmd.target_vgname);
661 break;
663 curves = build_sequential(drawing,
664 curves,
665 selection,
666 mmd.transition,
667 factor,
668 factor_start,
671 mmd.target_vgname);
672 break;
673 }
674
675 drawing.tag_topology_changed();
676}
677
679 const ModifierEvalContext *ctx,
680 blender::bke::GeometrySet *geometry_set)
681{
682 const auto *mmd = reinterpret_cast<GreasePencilBuildModifierData *>(md);
683
684 if (!geometry_set->has_grease_pencil()) {
685 return;
686 }
687
688 GreasePencil &grease_pencil = *geometry_set->get_grease_pencil_for_write();
689 const int eval_frame = grease_pencil.runtime->eval_frame;
690
691 IndexMaskMemory mask_memory;
693 grease_pencil, mmd->influence, mask_memory);
695 modifier::greasepencil::get_drawing_infos_by_layer(grease_pencil, layer_mask, eval_frame);
696
698 if (eval_frame < mmd->start_frame || eval_frame > mmd->end_frame) {
699 return;
700 }
701 }
702
703 const Scene &scene = *DEG_get_evaluated_scene(ctx->depsgraph);
704 const float scene_fps = float(scene.r.frs_sec) / scene.r.frs_sec_base;
705 const Span<const bke::greasepencil::Layer *> layers = grease_pencil.layers();
706
708 drawing_infos, [&](modifier::greasepencil::LayerDrawingInfo drawing_info) {
709 const bke::greasepencil::Layer &layer = *layers[drawing_info.layer_index];
710 const bke::greasepencil::Drawing *prev_drawing = grease_pencil.get_drawing_at(
711 layer, eval_frame - 1);
712
713 /* This will always return a valid start frame because we're iterating over the valid
714 * drawings on `eval_frame`. Each drawing will have a start frame. */
715 const int start_frame = *layer.start_frame_at(eval_frame);
716 BLI_assert(start_frame <= eval_frame);
717
718 const int relative_start_frame = eval_frame - start_frame;
719
720 const int frame_index = layer.sorted_keys_index_at(eval_frame);
721 BLI_assert(frame_index != -1);
722
723 int frame_duration = INT_MAX;
724 if (frame_index != layer.sorted_keys().index_range().last()) {
725 const int next_frame = layer.sorted_keys()[frame_index + 1];
726 frame_duration = math::distance(start_frame, next_frame);
727 }
728
729 build_drawing(*mmd,
730 *ctx->object,
731 *drawing_info.drawing,
732 prev_drawing,
733 relative_start_frame,
734 frame_duration,
735 scene_fps);
736 });
737}
738
739static void panel_draw(const bContext *C, Panel *panel)
740{
741 uiLayout *layout = panel->layout;
742
743 PointerRNA ob_ptr;
745
748
749 uiLayoutSetPropSep(layout, true);
750
751 /* First: Build mode and build settings. */
752 uiItemR(layout, ptr, "mode", UI_ITEM_NONE, nullptr, ICON_NONE);
754 uiItemR(layout, ptr, "transition", UI_ITEM_NONE, nullptr, ICON_NONE);
755 }
757 /* Concurrent mode doesn't support MOD_GREASE_PENCIL_BUILD_TIMEMODE_DRAWSPEED, so unset it. */
761 }
762 uiItemR(layout, ptr, "transition", UI_ITEM_NONE, nullptr, ICON_NONE);
763 }
764 uiItemS(layout);
765
766 /* Second: Time mode and time settings. */
767
768 uiItemR(layout, ptr, "time_mode", UI_ITEM_NONE, nullptr, ICON_NONE);
770 uiItemR(layout, ptr, "concurrent_time_alignment", UI_ITEM_NONE, nullptr, ICON_NONE);
771 }
772 switch (time_mode) {
774 uiItemR(layout, ptr, "speed_factor", UI_ITEM_NONE, nullptr, ICON_NONE);
775 uiItemR(layout, ptr, "speed_maxgap", UI_ITEM_NONE, nullptr, ICON_NONE);
776 break;
778 uiItemR(layout, ptr, "length", UI_ITEM_NONE, IFACE_("Frames"), ICON_NONE);
780 uiItemR(layout, ptr, "start_delay", UI_ITEM_NONE, nullptr, ICON_NONE);
781 }
782 break;
784 uiItemR(layout, ptr, "percentage_factor", UI_ITEM_NONE, nullptr, ICON_NONE);
785 break;
786 default:
787 break;
788 }
789 uiItemS(layout);
790 uiItemR(layout, ptr, "object", UI_ITEM_NONE, nullptr, ICON_NONE);
791
792 if (uiLayout *panel = uiLayoutPanelProp(
793 C, layout, ptr, "open_frame_range_panel", IFACE_("Effective Range")))
794 {
795 uiLayoutSetPropSep(panel, true);
796 uiItemR(
797 panel, ptr, "use_restrict_frame_range", UI_ITEM_NONE, IFACE_("Custom Range"), ICON_NONE);
798
799 const bool active = RNA_boolean_get(ptr, "use_restrict_frame_range");
800 uiLayout *col = uiLayoutColumn(panel, false);
801 uiLayoutSetActive(col, active);
802 uiItemR(col, ptr, "frame_start", UI_ITEM_NONE, IFACE_("Start"), ICON_NONE);
803 uiItemR(col, ptr, "frame_end", UI_ITEM_NONE, IFACE_("End"), ICON_NONE);
804 }
805
806 if (uiLayout *panel = uiLayoutPanelProp(C, layout, ptr, "open_fading_panel", IFACE_("Fading"))) {
807 uiLayoutSetPropSep(panel, true);
808 uiItemR(panel, ptr, "use_fading", UI_ITEM_NONE, IFACE_("Fade"), ICON_NONE);
809
810 const bool active = RNA_boolean_get(ptr, "use_fading");
811 uiLayout *col = uiLayoutColumn(panel, false);
812 uiLayoutSetActive(col, active);
813
814 uiItemR(col, ptr, "fade_factor", UI_ITEM_NONE, IFACE_("Factor"), ICON_NONE);
815
816 uiLayout *subcol = uiLayoutColumn(col, true);
817 uiItemR(subcol, ptr, "fade_thickness_strength", UI_ITEM_NONE, IFACE_("Thickness"), ICON_NONE);
818 uiItemR(subcol, 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 = uiLayoutPanelProp(
830 C, layout, ptr, "open_influence_panel", IFACE_("Influence")))
831 {
834 }
835
836 modifier_panel_end(layout, ptr);
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 BKE_modifier_copydata_generic(const ModifierData *md, ModifierData *md_dst, int flag)
@ eModifierTypeFlag_AcceptsGreasePencil
@ eModifierTypeFlag_EnableInEditmode
@ eModifierTypeFlag_SupportsEditmode
void(*)(void *user_data, Object *ob, ID **idpoin, int cb_flag) IDWalkFunc
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
Random number functions.
#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
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
#define C
Definition RandGen.cpp:29
void uiLayoutSetActive(uiLayout *layout, bool active)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemS(uiLayout *layout)
#define UI_ITEM_NONE
void uiItemPointerR(uiLayout *layout, PointerRNA *ptr, const char *propname, PointerRNA *searchptr, const char *searchpropname, const char *name, int icon)
PanelLayout uiLayoutPanelProp(const bContext *C, uiLayout *layout, PointerRNA *open_prop_owner, const char *open_prop_name)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
SIMD_FORCE_INLINE btScalar length(const btQuaternion &q)
Return the length of a quaternion.
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
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
OffsetIndices< int > points_by_curve() const
IndexRange curves_range() const
MutableAttributeAccessor attributes_for_write()
Span< float3 > positions() 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
local_group_size(16, 16) .push_constant(Type b
int len
draw_view in_light_buf[] float
uint col
ccl_device_inline float4 select(const int4 mask, const float4 a, const float4 b)
bke::CurvesGeometry reorder_curves_geometry(const bke::CurvesGeometry &src_curves, Span< int > old_by_new_map, const bke::AttributeFilter &attribute_filter)
Definition reorder.cc:258
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 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_layer_mask(const GreasePencil &grease_pencil, const std::optional< StringRef > layer_name_filter, const std::optional< int > layer_pass_filter, const bool layer_filter_invert, const bool layer_pass_filter_invert, IndexMaskMemory &memory)
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)
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:58
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(float t)
Definition noise.h:14
GPU_SHADER_INTERFACE_INFO(overlay_edit_curve_handle_iface, "vert").flat(Type pos vertex_in(1, Type::UINT, "data") .vertex_out(overlay_edit_curve_handle_iface) .geometry_layout(PrimitiveIn Frequency::GEOMETRY storage_buf(1, Qualifier::READ, "uint", "data[]", Frequency::GEOMETRY) .push_constant(Type Frequency::GEOMETRY selection[]
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:413
struct uiLayout * layout
struct RenderData r
GreasePencil * get_grease_pencil_for_write()
ccl_device_inline int abs(int x)
Definition util/math.h:120
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4126