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
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
46static void init_data(ModifierData *md)
47{
48 auto *gpmd = reinterpret_cast<GreasePencilBuildModifierData *>(md);
49
51
53 modifier::greasepencil::init_influence_data(&gpmd->influence, false);
54}
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
117 curves.ensure_evaluated_lengths();
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();
210 bke::MutableAttributeAccessor attributes = curves.attributes_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();
354 bke::MutableAttributeAccessor attributes = curves.attributes_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{
487 const OffsetIndices<int> points_by_curve = curves.points_by_curve();
488 const bke::AttributeAccessor attributes = curves.attributes();
489 const VArray<float> init_times = *attributes.lookup_or_default<float>(
490 "init_time", bke::AttrDomain::Curve, 0.0f);
491 const VArray<float> delta_times = *attributes.lookup_or_default<float>(
492 "delta_time", bke::AttrDomain::Point, 0.0f);
493
494 Array<float> start_times(curves.curves_num());
495 start_times[0] = 0;
496 float accumulated_shift_delta_time = init_times[0];
497 for (const int curve : curves.curves_range().drop_front(1)) {
498 const float previous_start_time = start_times[curve - 1];
499 const float previous_delta_time = delta_times[points_by_curve[curve - 1].last()];
500 const float previous_end_time = previous_start_time + previous_delta_time;
501
502 const float shifted_start_time = init_times[curve] - accumulated_shift_delta_time;
503 const float gap_delta_time = math::min(shifted_start_time - previous_end_time, max_gap);
504
505 start_times[curve] = previous_end_time + gap_delta_time;
506 accumulated_shift_delta_time += math::max(shifted_start_time - start_times[curve], 0.0f);
507 }
508 const float limit = time_elapsed * speed_fac;
509 for (const int curve : curves.curves_range()) {
510 const float start_time = start_times[curve];
511 for (const int point : points_by_curve[curve]) {
512 if (start_time + delta_times[point] >= limit) {
513 return math::clamp(float(point) / float(curves.points_num()), 0.0f, 1.0f);
514 }
515 }
516 }
517
518 return 1.0f;
519}
520
521static float get_build_factor(const GreasePencilBuildTimeMode time_mode,
522 const int current_frame,
523 const int start_frame,
524 const int length,
525 const float percentage,
526 const bke::CurvesGeometry &curves,
527 const float scene_fps,
528 const float speed_fac,
529 const float max_gap,
530 const float fade)
531{
532 const float build_factor_frames = math::clamp(
533 float(current_frame - start_frame) / length, 0.0f, 1.0f) *
534 (1.0f + fade);
535 switch (time_mode) {
537 return build_factor_frames;
539 return percentage * (1.0f + fade);
541 /* The "drawing speed" is written as an attribute called 'delta_time' (for each point). If
542 * this attribute doesn't exist, we fallback to the "frames" mode. */
543 if (!curves.attributes().contains("delta_time")) {
544 return build_factor_frames;
545 }
547 curves, float(current_frame) / scene_fps, speed_fac, max_gap) *
548 (1.0f + fade);
549 }
551 return 0.0f;
552}
553
555 const Object &ob,
557 const bke::greasepencil::Drawing *previous_drawing,
558 const int current_time,
559 const float scene_fps)
560{
562 bke::CurvesGeometry &curves = drawing.strokes_for_write();
563
564 if (curves.points_num() == 0) {
565 return;
566 }
567
568 IndexMaskMemory memory;
570 &ob, curves, mmd.influence, memory);
571
572 /* Remove a count of #prev_strokes. */
573 if (mmd.mode == MOD_GREASE_PENCIL_BUILD_MODE_ADDITIVE && previous_drawing != nullptr) {
574 const bke::CurvesGeometry &prev_curves = previous_drawing->strokes();
575 const int prev_strokes = prev_curves.curves_num();
576 const int added_strokes = curves.curves_num() - prev_strokes;
577 if (added_strokes > 0) {
578 Array<bool> work_on_select(curves.curves_num());
579 selection.to_bools(work_on_select.as_mutable_span());
580 work_on_select.as_mutable_span().take_front(prev_strokes).fill(false);
581 selection = IndexMask::from_bools(work_on_select, memory);
582 }
583 }
584
585 if (mmd.object) {
586 const int curves_num = curves.curves_num();
587 Array<bool> select(curves_num), reordered_select(curves_num);
588 selection.to_bools(select);
589 curves = reorder_strokes(
590 curves, select.as_span(), *mmd.object, reordered_select.as_mutable_span());
591 selection = IndexMask::from_bools(reordered_select, memory);
592 }
593
594 const float fade_factor = ((mmd.flag & MOD_GREASE_PENCIL_BUILD_USE_FADING) != 0) ? mmd.fade_fac :
595 0.0f;
597 current_time,
598 mmd.start_delay,
599 mmd.length,
600 mmd.percentage_fac,
601 curves,
602 scene_fps,
603 mmd.speed_fac,
604 mmd.speed_maxgap,
605 fade_factor);
606 float factor_start = factor - fade_factor;
608 std::swap(factor, factor_start);
609 }
610
611 const float use_time_alignment = mmd.transition != MOD_GREASE_PENCIL_BUILD_TRANSITION_GROW ?
612 !mmd.time_alignment :
613 mmd.time_alignment;
614 switch (mmd.mode) {
615 default:
617 curves = build_sequential(drawing,
618 curves,
619 selection,
620 mmd.transition,
621 factor,
622 factor_start,
625 mmd.target_vgname);
626 break;
628 curves = build_concurrent(drawing,
629 curves,
630 selection,
631 use_time_alignment,
632 mmd.transition,
633 factor,
634 factor_start,
637 mmd.target_vgname);
638 break;
640 curves = build_sequential(drawing,
641 curves,
642 selection,
643 mmd.transition,
644 factor,
645 factor_start,
648 mmd.target_vgname);
649 break;
650 }
651
652 drawing.tag_topology_changed();
653}
654
656 const ModifierEvalContext *ctx,
657 blender::bke::GeometrySet *geometry_set)
658{
659 const auto *mmd = reinterpret_cast<GreasePencilBuildModifierData *>(md);
660
661 if (!geometry_set->has_grease_pencil()) {
662 return;
663 }
664
665 GreasePencil &grease_pencil = *geometry_set->get_grease_pencil_for_write();
666 const int eval_frame = grease_pencil.runtime->eval_frame;
667
668 IndexMaskMemory mask_memory;
670 grease_pencil, mmd->influence, mask_memory);
672 modifier::greasepencil::get_drawing_infos_by_layer(grease_pencil, layer_mask, eval_frame);
673
675 if (eval_frame < mmd->start_frame || eval_frame > mmd->end_frame) {
676 return;
677 }
678 }
679
680 const Scene &scene = *DEG_get_evaluated_scene(ctx->depsgraph);
681 const float scene_fps = float(scene.r.frs_sec) / scene.r.frs_sec_base;
682 const Span<const bke::greasepencil::Layer *> layers = grease_pencil.layers();
683
685 drawing_infos, [&](modifier::greasepencil::LayerDrawingInfo drawing_info) {
686 const bke::greasepencil::Layer &layer = *layers[drawing_info.layer_index];
687 const bke::greasepencil::Drawing *prev_drawing = grease_pencil.get_drawing_at(
688 layer, eval_frame - 1);
689
690 /* This will always return a valid start frame because we're iterating over the valid
691 * drawings on `eval_frame`. Each drawing will have a start frame. */
692 const int start_frame = *layer.start_frame_at(eval_frame);
693 BLI_assert(start_frame <= eval_frame);
694
695 const int relative_start_frame = eval_frame - start_frame;
696
697 const int frame_index = layer.sorted_keys_index_at(eval_frame);
698 BLI_assert(frame_index != -1);
699
700 int time = relative_start_frame;
701 if (frame_index != layer.sorted_keys().index_range().last()) {
702 const int next_frame = layer.sorted_keys()[frame_index + 1];
703 const int frame_duration = math::distance(start_frame, next_frame);
704 time = math::round(float(relative_start_frame) /
705 math::min(float(frame_duration), mmd->length) * mmd->length);
706 }
707
708 build_drawing(*mmd, *ctx->object, *drawing_info.drawing, prev_drawing, time, scene_fps);
709 });
710}
711
712static void panel_draw(const bContext *C, Panel *panel)
713{
714 uiLayout *layout = panel->layout;
715
716 PointerRNA ob_ptr;
718
721
722 uiLayoutSetPropSep(layout, true);
723
724 /* First: Build mode and build settings. */
725 uiItemR(layout, ptr, "mode", UI_ITEM_NONE, nullptr, ICON_NONE);
727 uiItemR(layout, ptr, "transition", UI_ITEM_NONE, nullptr, ICON_NONE);
728 }
730 /* Concurrent mode doesn't support MOD_GREASE_PENCIL_BUILD_TIMEMODE_DRAWSPEED, so unset it. */
734 }
735 uiItemR(layout, ptr, "transition", UI_ITEM_NONE, nullptr, ICON_NONE);
736 }
737 uiItemS(layout);
738
739 /* Second: Time mode and time settings. */
740
741 uiItemR(layout, ptr, "time_mode", UI_ITEM_NONE, nullptr, ICON_NONE);
743 uiItemR(layout, ptr, "concurrent_time_alignment", UI_ITEM_NONE, nullptr, ICON_NONE);
744 }
745 switch (time_mode) {
747 uiItemR(layout, ptr, "speed_factor", UI_ITEM_NONE, nullptr, ICON_NONE);
748 uiItemR(layout, ptr, "speed_maxgap", UI_ITEM_NONE, nullptr, ICON_NONE);
749 break;
751 uiItemR(layout, ptr, "length", UI_ITEM_NONE, IFACE_("Frames"), ICON_NONE);
753 uiItemR(layout, ptr, "start_delay", UI_ITEM_NONE, nullptr, ICON_NONE);
754 }
755 break;
757 uiItemR(layout, ptr, "percentage_factor", UI_ITEM_NONE, nullptr, ICON_NONE);
758 break;
759 default:
760 break;
761 }
762 uiItemS(layout);
763 uiItemR(layout, ptr, "object", UI_ITEM_NONE, nullptr, ICON_NONE);
764
765 if (uiLayout *panel = uiLayoutPanelProp(
766 C, layout, ptr, "open_frame_range_panel", IFACE_("Effective Range")))
767 {
768 uiLayoutSetPropSep(panel, true);
769 uiItemR(
770 panel, ptr, "use_restrict_frame_range", UI_ITEM_NONE, IFACE_("Custom Range"), ICON_NONE);
771
772 const bool active = RNA_boolean_get(ptr, "use_restrict_frame_range");
773 uiLayout *col = uiLayoutColumn(panel, false);
774 uiLayoutSetActive(col, active);
775 uiItemR(col, ptr, "frame_start", UI_ITEM_NONE, IFACE_("Start"), ICON_NONE);
776 uiItemR(col, ptr, "frame_end", UI_ITEM_NONE, IFACE_("End"), ICON_NONE);
777 }
778
779 if (uiLayout *panel = uiLayoutPanelProp(C, layout, ptr, "open_fading_panel", IFACE_("Fading"))) {
780 uiLayoutSetPropSep(panel, true);
781 uiItemR(panel, ptr, "use_fading", UI_ITEM_NONE, IFACE_("Fade"), ICON_NONE);
782
783 const bool active = RNA_boolean_get(ptr, "use_fading");
784 uiLayout *col = uiLayoutColumn(panel, false);
785 uiLayoutSetActive(col, active);
786
787 uiItemR(col, ptr, "fade_factor", UI_ITEM_NONE, IFACE_("Factor"), ICON_NONE);
788
789 uiLayout *subcol = uiLayoutColumn(col, true);
790 uiItemR(subcol, ptr, "fade_thickness_strength", UI_ITEM_NONE, IFACE_("Thickness"), ICON_NONE);
791 uiItemR(subcol, ptr, "fade_opacity_strength", UI_ITEM_NONE, IFACE_("Opacity"), ICON_NONE);
792
794 ptr,
795 "target_vertex_group",
796 &ob_ptr,
797 "vertex_groups",
798 IFACE_("Weight Output"),
799 ICON_NONE);
800 }
801
802 if (uiLayout *influence_panel = uiLayoutPanelProp(
803 C, layout, ptr, "open_influence_panel", IFACE_("Influence")))
804 {
807 }
808
809 modifier_panel_end(layout, ptr);
810}
811
816
817} // namespace blender
818
820 /*idname*/ "GreasePencilBuildModifier",
821 /*name*/ N_("Build"),
822 /*struct_name*/ "GreasePencilBuildModifierData",
823 /*struct_size*/ sizeof(GreasePencilBuildModifierData),
824 /*srna*/ &RNA_GreasePencilBuildModifier,
826 /*flags*/
829 /*icon*/ ICON_MOD_LENGTH,
830
831 /*copy_data*/ blender::copy_data,
832
833 /*deform_verts*/ nullptr,
834 /*deform_matrices*/ nullptr,
835 /*deform_verts_EM*/ nullptr,
836 /*deform_matrices_EM*/ nullptr,
837 /*modify_mesh*/ nullptr,
838 /*modify_geometry_set*/ blender::modify_geometry_set,
839
840 /*init_data*/ blender::init_data,
841 /*required_data_mask*/ nullptr,
842 /*free_data*/ blender::free_data,
843 /*is_disabled*/ nullptr,
844 /*update_depsgraph*/ blender::update_depsgraph,
845 /*depends_on_time*/ nullptr,
846 /*depends_on_normals*/ nullptr,
847 /*foreach_ID_link*/ blender::foreach_ID_link,
848 /*foreach_tex_link*/ nullptr,
849 /*free_runtime_data*/ nullptr,
850 /*panel_register*/ blender::panel_register,
851 /*blend_write*/ blender::blend_write,
852 /*blend_read*/ blender::blend_read,
853};
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
struct GreasePencilBuildModifierData GreasePencilBuildModifierData
@ 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
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)
int64_t size() const
Definition BLI_array.hh:245
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 & first() const
Definition BLI_array.hh:270
const T * begin() const
Definition BLI_array.hh:310
MutableAttributeAccessor attributes_for_write()
MutableSpan< int > offsets_for_write()
MutableSpan< float > opacities_for_write()
MutableSpan< float > radii_for_write()
bke::CurvesGeometry & strokes_for_write()
const bke::CurvesGeometry & strokes() const
static IndexMask from_bools(Span< bool > bools, IndexMaskMemory &memory)
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 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 void build_drawing(const GreasePencilBuildModifierData &mmd, const Object &ob, bke::greasepencil::Drawing &drawing, const bke::greasepencil::Drawing *previous_drawing, const int current_time, const float scene_fps)
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 panel_register(ARegionType *region_type)
static float get_factor_from_draw_speed(const bke::CurvesGeometry &curves, const float time_elapsed, const float speed_fac, const float max_gap)
static float get_build_factor(const GreasePencilBuildTimeMode time_mode, const int current_frame, const int start_frame, 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 update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
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
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
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