Blender V4.5
MOD_grease_pencil_time.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_index_range.hh"
10#include "BLI_map.hh"
11#include "BLI_span.hh"
12#include "BLI_string.h"
13#include "BLI_string_utf8.h"
14
15#include "DNA_defaults.h"
16#include "DNA_modifier_types.h"
17#include "DNA_scene_types.h"
18
19#include "BKE_curves.hh"
20#include "BKE_geometry_set.hh"
21#include "BKE_grease_pencil.hh"
22#include "BKE_instances.hh"
23#include "BKE_modifier.hh"
24#include "BKE_screen.hh"
25
26#include "BLO_read_write.hh"
27
29
30#include "UI_interface.hh"
31#include "UI_resources.hh"
32
33#include "BLT_translation.hh"
34
35#include "WM_api.hh"
36#include "WM_types.hh"
37
38#include "RNA_access.hh"
39#include "RNA_prototypes.hh"
40
42#include "MOD_ui_common.hh"
43
44namespace blender {
45
46static void init_data(ModifierData *md)
47{
48 auto *tmd = reinterpret_cast<GreasePencilTimeModifierData *>(md);
49
51
53 modifier::greasepencil::init_influence_data(&tmd->influence, false);
54
57 STRNCPY_UTF8(segment->name, DATA_("Segment"));
58 tmd->segments_array = segment;
59 tmd->segments_num = 1;
60}
61
62static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
63{
64 const auto *tmd = reinterpret_cast<const GreasePencilTimeModifierData *>(md);
65 auto *tmmd = reinterpret_cast<GreasePencilTimeModifierData *>(target);
66
68
70 modifier::greasepencil::copy_influence_data(&tmd->influence, &tmmd->influence, flag);
71
72 tmmd->segments_array = static_cast<GreasePencilTimeModifierSegment *>(
73 MEM_dupallocN(tmd->segments_array));
74}
75
76static void free_data(ModifierData *md)
77{
78 auto *tmd = reinterpret_cast<GreasePencilTimeModifierData *>(md);
80
81 MEM_SAFE_FREE(tmd->segments_array);
82}
83
84static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
85{
86 auto *tmd = reinterpret_cast<GreasePencilTimeModifierData *>(md);
87 modifier::greasepencil::foreach_influence_ID_link(&tmd->influence, ob, walk, user_data);
88}
89
90struct FrameRange {
91 /* Start frame. */
92 int sfra;
93 /* End frame (unlimited range when undefined). */
94 int efra;
95
96 bool is_empty() const
97 {
98 return efra < sfra;
99 }
100
101 bool is_single_frame() const
102 {
103 return efra == sfra;
104 }
105
106 int duration() const
107 {
108 return std::max(efra + 1 - sfra, 0);
109 }
110
111 FrameRange drop_front(const int n) const
112 {
113 BLI_assert(n >= 0);
114 return FrameRange{std::min(sfra + n, efra), efra};
115 }
116
117 FrameRange drop_back(const int n) const
118 {
119 BLI_assert(n >= 0);
120 return FrameRange{sfra, std::max(efra - n, sfra)};
121 }
122
123 FrameRange shift(const int n) const
124 {
125 return FrameRange{sfra + n, efra + n};
126 }
127};
128
134static IndexRange find_key_range(const Span<int> sorted_keys, const FrameRange &frame_range)
135{
136 IndexRange result = sorted_keys.index_range();
137 for (const int i : result.index_range()) {
138 const int irev = result.size() - 1 - i;
139 if (sorted_keys[result[irev]] <= frame_range.sfra) {
140 /* Found first key affecting the frame range, drop any earlier keys. */
141 result = result.drop_front(irev);
142 break;
143 }
144 }
145 for (const int i : result.index_range()) {
146 if (sorted_keys[result[i]] > frame_range.efra) {
147 /* Found first key outside the frame range, drop this and later keys. */
148 result = result.take_front(i);
149 break;
150 }
151 }
152 return result;
153}
154
156 private:
157 float offset_;
158 float scale_;
159 bool use_loop_;
160
161 public:
163 : offset_(tmd.offset),
164 scale_(tmd.frame_scale),
166 {
167 }
168
169 float offset() const
170 {
171 return offset_;
172 }
173 float scale() const
174 {
175 return scale_;
176 }
177 bool use_loop() const
178 {
179 return use_loop_;
180 }
181
182 float to_scene_time(const float local_frame) const
183 {
184 return float(local_frame - offset_) / scale_;
185 }
186 float to_local_time(const float scene_frame) const
187 {
188 return scene_frame * scale_ + offset_;
189 }
190
191 /* Compute scene frame number on or after the local frame. */
192 int scene_frame_before_local_frame(const int local_frame) const
193 {
194 return int(math::floor(to_scene_time(local_frame)));
195 }
196 /* Compute scene frame number on or after the local frame. */
197 int scene_frame_after_local_frame(const int local_frame) const
198 {
199 return int(math::ceil(to_scene_time(local_frame)));
200 }
201
202 /* Compute local frame number on or before the scene frame. */
203 int local_frame_before_scene_frame(const int scene_frame) const
204 {
205 return int(math::floor(to_local_time(scene_frame)));
206 }
207 /* Compute local frame number on or after the scene frame. */
208 int local_frame_after_scene_frame(const int scene_frame) const
209 {
210 return int(math::ceil(to_local_time(scene_frame)));
211 }
212};
213
214/* Determine how many times the source range must be repeated to cover the destination range. */
215static void calculate_repetitions(const TimeMapping &mapping,
216 const FrameRange &gp_src,
217 const FrameRange &scene_dst,
218 int &r_start,
219 int &r_count)
220{
221 if (!mapping.use_loop()) {
222 r_start = 0;
223 r_count = 1;
224 return;
225 }
226 const int duration = gp_src.duration();
227 if (duration <= 0) {
228 r_start = 0;
229 r_count = 0;
230 return;
231 }
232 const FrameRange gp_dst = {mapping.local_frame_before_scene_frame(scene_dst.sfra),
233 mapping.local_frame_after_scene_frame(scene_dst.efra)};
234 r_start = math::floor(float(gp_dst.sfra - gp_src.sfra) / float(duration));
235 r_count = math::floor(float(gp_dst.efra - gp_src.sfra) / float(duration)) + 1 - r_start;
236}
237
238static void insert_keys_forward(const TimeMapping &mapping,
239 const Map<int, GreasePencilFrame> &frames,
240 const Span<int> sorted_keys,
241 const FrameRange gp_src_range,
242 const FrameRange gp_dst_range,
243 Map<int, GreasePencilFrame> &dst_frames)
244{
245 const int offset = gp_dst_range.sfra - gp_src_range.sfra;
246 for (const int i : sorted_keys.index_range()) {
247 const int gp_key = sorted_keys[i];
248 const int gp_insert_key = std::max(gp_key, gp_src_range.sfra);
249 if (gp_insert_key > gp_src_range.efra) {
250 continue;
251 }
252
253 const int scene_key = mapping.scene_frame_after_local_frame(gp_insert_key + offset);
254 dst_frames.add_overwrite(scene_key, frames.lookup(gp_key));
255 }
256}
257
258/* Insert keys in reverse order. */
259static void insert_keys_reverse(const TimeMapping &mapping,
260 const Map<int, GreasePencilFrame> &frames,
261 const Span<int> sorted_keys,
262 const FrameRange gp_src_range,
263 const FrameRange gp_dst_range,
264 Map<int, GreasePencilFrame> &dst_frames)
265{
266 const int offset = gp_dst_range.sfra - gp_src_range.sfra;
267 for (const int i : sorted_keys.index_range()) {
268 /* In reverse mode keys need to be inserted in reverse order to ensure "earlier" frames can
269 * overwrite "later" frames. */
270 const int irev = sorted_keys.size() - 1 - i;
271 /* This finds the correct scene frame starting at the end of the frame interval. */
272 const int gp_key = sorted_keys[irev];
273 /* The insertion scene time is the end of the keyframe interval instead of the start.
274 * This is the frame after the end frame (efra) to cover the full extent of the end frame
275 * interval. */
276 const int gp_end_key = (irev < sorted_keys.size() - 1) ?
277 std::min(sorted_keys[irev + 1], gp_src_range.efra + 1) :
278 gp_src_range.efra + 1;
279 if (gp_end_key < gp_src_range.sfra) {
280 return;
281 }
282
283 /* Reverse key frame inside the range. */
284 const int gp_key_rev = gp_src_range.efra + 1 - (gp_end_key - gp_src_range.sfra);
285 const int scene_key = mapping.scene_frame_after_local_frame(gp_key_rev + offset);
286 dst_frames.add_overwrite(scene_key, frames.lookup(gp_key));
287 }
288}
289
290static void fill_scene_range_fixed(const TimeMapping &mapping,
291 const Map<int, GreasePencilFrame> &frames,
292 const Span<int> sorted_keys,
293 const int gp_src_frame,
294 const FrameRange scene_dst_range,
295 Map<int, GreasePencilFrame> &dst_frames)
296{
297 const FrameRange gp_src_range = {gp_src_frame, gp_src_frame};
298 const FrameRange gp_dst_range = {mapping.local_frame_before_scene_frame(scene_dst_range.sfra),
299 mapping.local_frame_after_scene_frame(scene_dst_range.efra)};
300
301 const Span<int> src_keys = sorted_keys.slice(find_key_range(sorted_keys, gp_src_range));
302 insert_keys_forward(mapping, frames, src_keys, gp_src_range, gp_dst_range, dst_frames);
303}
304
305static void fill_scene_range_forward(const TimeMapping &mapping,
306 const Map<int, GreasePencilFrame> &frames,
307 const Span<int> sorted_keys,
308 const FrameRange gp_src_range,
309 const FrameRange scene_dst_range,
310 Map<int, GreasePencilFrame> &dst_frames)
311{
312 int repeat_start = 0, repeat_count = 1;
313 calculate_repetitions(mapping, gp_src_range, scene_dst_range, repeat_start, repeat_count);
314
315 const Span<int> src_keys = sorted_keys.slice(find_key_range(sorted_keys, gp_src_range));
316 FrameRange gp_dst_range = gp_src_range.shift(repeat_start * gp_src_range.duration());
317 for ([[maybe_unused]] const int repeat_i : IndexRange(repeat_count)) {
318 insert_keys_forward(mapping, frames, src_keys, gp_src_range, gp_dst_range, dst_frames);
319 gp_dst_range = gp_dst_range.shift(gp_src_range.duration());
320 }
321}
322
323static void fill_scene_range_reverse(const TimeMapping &mapping,
324 const Map<int, GreasePencilFrame> &frames,
325 const Span<int> sorted_keys,
326 const FrameRange gp_src_range,
327 const FrameRange scene_dst_range,
328 Map<int, GreasePencilFrame> &dst_frames)
329{
330 int repeat_start = 0, repeat_count = 1;
331 calculate_repetitions(mapping, gp_src_range, scene_dst_range, repeat_start, repeat_count);
332
333 const Span<int> src_keys = sorted_keys.slice(find_key_range(sorted_keys, gp_src_range));
334 FrameRange gp_dst_range = gp_src_range.shift(repeat_start * gp_src_range.duration());
335 for ([[maybe_unused]] const int repeat_i : IndexRange(repeat_count)) {
336 insert_keys_reverse(mapping, frames, src_keys, gp_src_range, gp_dst_range, dst_frames);
337 gp_dst_range = gp_dst_range.shift(gp_src_range.duration());
338 }
339}
340
341static void fill_scene_range_ping_pong(const TimeMapping &mapping,
342 const Map<int, GreasePencilFrame> &frames,
343 const Span<int> sorted_keys,
344 const FrameRange gp_src_range,
345 const FrameRange scene_dst_range,
346 Map<int, GreasePencilFrame> &dst_frames)
347{
348 /* Double interval for ping-pong mode, start and end frame only appear once. */
349 const FrameRange gp_src_range_ping = {gp_src_range.sfra, gp_src_range.efra - 1};
350 const FrameRange gp_src_range_pong = {gp_src_range.sfra + 1, gp_src_range.efra};
351 const FrameRange gp_range_full = {gp_src_range.sfra,
352 2 * gp_src_range.efra - gp_src_range.sfra - 1};
353 int repeat_start = 0, repeat_count = 1;
354 calculate_repetitions(mapping, gp_range_full, scene_dst_range, repeat_start, repeat_count);
355
356 const Span<int> src_keys = sorted_keys.slice(find_key_range(sorted_keys, gp_src_range));
357 FrameRange gp_dst_range = gp_src_range.shift(repeat_start * gp_range_full.duration());
358 for ([[maybe_unused]] const int repeat_i : IndexRange(repeat_count)) {
359 /* Ping. */
360 insert_keys_forward(mapping, frames, src_keys, gp_src_range, gp_dst_range, dst_frames);
361 gp_dst_range = gp_dst_range.shift(gp_src_range_ping.duration());
362 /* Pong. */
363 insert_keys_reverse(mapping, frames, src_keys, gp_src_range, gp_dst_range, dst_frames);
364 gp_dst_range = gp_dst_range.shift(gp_src_range_pong.duration());
365 }
366}
367
368static void fill_scene_range_chain(const TimeMapping &mapping,
369 const Map<int, GreasePencilFrame> &frames,
370 const Span<int> sorted_keys,
372 const FrameRange gp_src_range,
373 const FrameRange scene_dst_range,
374 Map<int, GreasePencilFrame> &dst_frames)
375{
376 using Segment = GreasePencilTimeModifierSegment;
377
378 if (segments.is_empty()) {
379 return;
380 }
381 /* Segment settings tolerate start frame after end frame. */
382 auto segment_base_range = [](const Segment &segment) {
383 return FrameRange{std::min(segment.segment_start, segment.segment_end),
384 std::max(segment.segment_start, segment.segment_end)};
385 };
386 auto segment_full_range = [](const Segment &segment) {
387 const FrameRange base_range = FrameRange{std::min(segment.segment_start, segment.segment_end),
388 std::max(segment.segment_start, segment.segment_end)};
389 const int base_duration = (segment.segment_mode == MOD_GREASE_PENCIL_TIME_SEG_MODE_PINGPONG ?
390 base_range.duration() * 2 - 2 :
391 base_range.duration());
392 return FrameRange{base_range.sfra,
393 base_range.sfra + segment.segment_repeat * base_duration - 1};
394 };
395 /* Find src range by adding up all segments. */
396 const FrameRange gp_range_full = [&]() {
397 int duration = segment_full_range(segments.first()).duration();
398 for (const Segment &segment : segments.drop_front(1)) {
399 duration += segment_full_range(segment).duration();
400 }
401 /* Same start as the source range. */
402 return FrameRange{gp_src_range.sfra, gp_src_range.sfra + duration - 1};
403 }();
404 int repeat_start = 0, repeat_count = 1;
405 calculate_repetitions(mapping, gp_range_full, scene_dst_range, repeat_start, repeat_count);
406
407 const Span<int> src_keys = sorted_keys;
408
409 FrameRange gp_dst_range = gp_src_range.shift(repeat_start * gp_range_full.duration());
410 for ([[maybe_unused]] const int repeat_i : IndexRange(repeat_count)) {
411 for (const Segment &segment : segments) {
412 const FrameRange segment_src_range = segment_base_range(segment);
413 for ([[maybe_unused]] const int segment_repeat_i : IndexRange(segment.segment_repeat)) {
414 switch (GreasePencilTimeModifierSegmentMode(segment.segment_mode)) {
417 mapping, frames, src_keys, segment_src_range, gp_dst_range, dst_frames);
418 gp_dst_range = gp_dst_range.shift(segment_src_range.duration());
419 break;
422 mapping, frames, src_keys, segment_src_range, gp_dst_range, dst_frames);
423 gp_dst_range = gp_dst_range.shift(segment_src_range.duration());
424 break;
426 /* Ping. */
427 const FrameRange segment_src_range_ping = {segment_src_range.sfra,
428 segment_src_range.efra - 1};
430 mapping, frames, src_keys, segment_src_range_ping, gp_dst_range, dst_frames);
431 gp_dst_range = gp_dst_range.shift(segment_src_range_ping.duration());
432 /* Pong. */
433 const FrameRange segment_src_range_pong = {segment_src_range.sfra + 1,
434 segment_src_range.efra};
436 mapping, frames, src_keys, segment_src_range_pong, gp_dst_range, dst_frames);
437 gp_dst_range = gp_dst_range.shift(segment_src_range_pong.duration());
438 break;
439 }
440 }
441 }
442 }
443 }
444}
445
447 const Scene &eval_scene,
448 const Map<int, GreasePencilFrame> &frames,
449 const Span<int> sorted_keys,
450 const FrameRange scene_dst_range,
451 Map<int, GreasePencilFrame> &dst_frames)
452{
453 const TimeMapping mapping(tmd);
454 const auto mode = GreasePencilTimeModifierMode(tmd.mode);
455 const bool use_custom_range = tmd.flag & MOD_GREASE_PENCIL_TIME_CUSTOM_RANGE;
456
457 const FrameRange scene_range = FrameRange{eval_scene.r.sfra, eval_scene.r.efra};
458 const FrameRange custom_range = use_custom_range ? FrameRange{tmd.sfra, tmd.efra} : scene_range;
459
460 switch (mode) {
463 tmd, frames, sorted_keys, custom_range, scene_dst_range, dst_frames);
464 break;
467 tmd, frames, sorted_keys, custom_range, scene_dst_range, dst_frames);
468 break;
470 fill_scene_range_fixed(tmd, frames, sorted_keys, tmd.offset, scene_dst_range, dst_frames);
471 break;
474 tmd, frames, sorted_keys, custom_range, scene_dst_range, dst_frames);
475 break;
478 tmd, frames, sorted_keys, tmd.segments(), scene_range, scene_dst_range, dst_frames);
479 break;
480 }
481}
482
484 const ModifierEvalContext *ctx,
485 bke::GeometrySet *geometry_set)
486{
489
490 auto *tmd = reinterpret_cast<GreasePencilTimeModifierData *>(md);
491 const Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
492 /* Just include the current frame for now. The method can be applied to arbitrary ranges. */
493 const FrameRange dst_keyframe_range = {scene->r.cfra, scene->r.cfra};
494
495 if (!geometry_set->has_grease_pencil()) {
496 return;
497 }
498 GreasePencil &grease_pencil = *geometry_set->get_grease_pencil_for_write();
499
500 IndexMaskMemory mask_memory;
502 grease_pencil, tmd->influence, mask_memory);
503
504 const Span<Layer *> layers_for_write = grease_pencil.layers_for_write();
505 layer_mask.foreach_index([&](const int64_t layer_i) {
506 Layer &layer = *layers_for_write[layer_i];
507 const Span<int> sorted_keys = layer.sorted_keys();
508 const Map<int, GreasePencilFrame> &src_frames = layer.frames();
509
511 fill_scene_timeline(*tmd, *scene, src_frames, sorted_keys, dst_keyframe_range, new_frames);
512 layer.frames_for_write() = std::move(new_frames);
514 });
515}
516
517static void panel_draw(const bContext *C, Panel *panel)
518{
519 uiLayout *layout = panel->layout;
520
521 PointerRNA ob_ptr;
523 auto *tmd = static_cast<GreasePencilTimeModifierData *>(ptr->data);
524 const auto mode = GreasePencilTimeModifierMode(RNA_enum_get(ptr, "mode"));
525 const bool use_fixed_offset = (mode == MOD_GREASE_PENCIL_TIME_MODE_FIX);
526 const bool use_custom_range = !ELEM(
528 uiLayout *row, *col;
529
530 uiLayoutSetPropSep(layout, true);
531
532 layout->prop(ptr, "mode", UI_ITEM_NONE, std::nullopt, ICON_NONE);
533
534 col = &layout->column(false);
535
536 const char *text = use_fixed_offset ? IFACE_("Frame") : IFACE_("Frame Offset");
537 col->prop(ptr, "offset", UI_ITEM_NONE, text, ICON_NONE);
538
539 row = &col->row(false);
540 uiLayoutSetActive(row, !use_fixed_offset);
541 row->prop(ptr, "frame_scale", UI_ITEM_NONE, IFACE_("Scale"), ICON_NONE);
542
543 row = &layout->row(false);
544 uiLayoutSetActive(row, !use_fixed_offset);
545 row->prop(ptr, "use_keep_loop", UI_ITEM_NONE, std::nullopt, ICON_NONE);
546
548 row = &layout->row(false);
549 uiLayoutSetPropSep(row, false);
550
551 uiTemplateList(row,
552 (bContext *)C,
553 "MOD_UL_grease_pencil_time_modifier_segments",
554 "",
555 ptr,
556 "segments",
557 ptr,
558 "segment_active_index",
559 nullptr,
560 3,
561 10,
562 0,
563 1,
565
566 col = &row->column(false);
567
568 uiLayout *sub = &col->column(true);
569 sub->op("OBJECT_OT_grease_pencil_time_modifier_segment_add", "", ICON_ADD);
570 sub->op("OBJECT_OT_grease_pencil_time_modifier_segment_remove", "", ICON_REMOVE);
571 col->separator();
572 sub = &col->column(true);
574 sub, "", ICON_TRIA_UP, "OBJECT_OT_grease_pencil_time_modifier_segment_move", "type", "UP");
576 "",
577 ICON_TRIA_DOWN,
578 "OBJECT_OT_grease_pencil_time_modifier_segment_move",
579 "type",
580 "DOWN");
581
582 if (tmd->segments().index_range().contains(tmd->segment_active_index)) {
584 ptr->owner_id,
585 &RNA_GreasePencilTimeModifierSegment,
586 &tmd->segments()[tmd->segment_active_index]);
587
588 sub = &layout->column(true);
589 sub->prop(&segment_ptr, "segment_mode", UI_ITEM_NONE, std::nullopt, ICON_NONE);
590 sub = &layout->column(true);
591 sub->prop(&segment_ptr, "segment_start", UI_ITEM_NONE, std::nullopt, ICON_NONE);
592 sub->prop(&segment_ptr, "segment_end", UI_ITEM_NONE, std::nullopt, ICON_NONE);
593 sub->prop(&segment_ptr, "segment_repeat", UI_ITEM_NONE, std::nullopt, ICON_NONE);
594 }
595 }
596
597 PanelLayout custom_range_panel_layout = layout->panel_prop(C, ptr, "open_custom_range_panel");
598 if (uiLayout *header = custom_range_panel_layout.header) {
599 uiLayoutSetPropSep(header, false);
600 uiLayoutSetActive(header, use_custom_range);
601 header->prop(ptr, "use_custom_frame_range", UI_ITEM_NONE, std::nullopt, ICON_NONE);
602 }
603 if (uiLayout *body = custom_range_panel_layout.body) {
604 uiLayoutSetPropSep(body, true);
605 uiLayoutSetActive(body, use_custom_range && RNA_boolean_get(ptr, "use_custom_frame_range"));
606
607 col = &body->column(true);
608 col->prop(ptr, "frame_start", UI_ITEM_NONE, IFACE_("Frame Start"), ICON_NONE);
609 col->prop(ptr, "frame_end", UI_ITEM_NONE, IFACE_("End"), ICON_NONE);
610 }
611
612 if (uiLayout *influence_panel = layout->panel_prop(
613 C, ptr, "open_influence_panel", IFACE_("Influence")))
614 {
616 }
617
619}
620
621static void segment_list_item_draw(uiList * /*ui_list*/,
622 const bContext * /*C*/,
623 uiLayout *layout,
624 PointerRNA * /*idataptr*/,
625 PointerRNA *itemptr,
626 int /*icon*/,
627 PointerRNA * /*active_dataptr*/,
628 const char * /*active_propname*/,
629 int /*index*/,
630 int /*flt_flag*/)
631{
632 uiLayout *row = &layout->row(true);
633 row->prop(itemptr, "name", UI_ITEM_R_NO_BG, "", ICON_NONE);
634}
635
636static void panel_register(ARegionType *region_type)
637{
639
640 uiListType *list_type = MEM_callocN<uiListType>("Grease Pencil Time modifier segments");
641 STRNCPY(list_type->idname, "MOD_UL_grease_pencil_time_modifier_segments");
643 WM_uilisttype_add(list_type);
644}
645
646static void blend_write(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md)
647{
648 const auto *tmd = reinterpret_cast<const GreasePencilTimeModifierData *>(md);
649
651 modifier::greasepencil::write_influence_data(writer, &tmd->influence);
652
654 writer, GreasePencilTimeModifierSegment, tmd->segments_num, tmd->segments_array);
655}
656
657static void blend_read(BlendDataReader *reader, ModifierData *md)
658{
659 auto *tmd = reinterpret_cast<GreasePencilTimeModifierData *>(md);
660
661 modifier::greasepencil::read_influence_data(reader, &tmd->influence);
662
664 reader, GreasePencilTimeModifierSegment, tmd->segments_num, &tmd->segments_array);
665}
666
667} // namespace blender
668
670 /*idname*/ "GreasePencilTime",
671 /*name*/ N_("TimeOffset"),
672 /*struct_name*/ "GreasePencilTimeModifierData",
673 /*struct_size*/ sizeof(GreasePencilTimeModifierData),
674 /*srna*/ &RNA_GreasePencilTimeModifier,
678 /*icon*/ ICON_MOD_TIME,
679
680 /*copy_data*/ blender::copy_data,
681
682 /*deform_verts*/ nullptr,
683 /*deform_matrices*/ nullptr,
684 /*deform_verts_EM*/ nullptr,
685 /*deform_matrices_EM*/ nullptr,
686 /*modify_mesh*/ nullptr,
687 /*modify_geometry_set*/ blender::modify_geometry_set,
688
689 /*init_data*/ blender::init_data,
690 /*required_data_mask*/ nullptr,
691 /*free_data*/ blender::free_data,
692 /*is_disabled*/ nullptr,
693 /*update_depsgraph*/ nullptr,
694 /*depends_on_time*/ nullptr,
695 /*depends_on_normals*/ nullptr,
696 /*foreach_ID_link*/ blender::foreach_ID_link,
697 /*foreach_tex_link*/ nullptr,
698 /*free_runtime_data*/ nullptr,
699 /*panel_register*/ blender::panel_register,
700 /*blend_write*/ blender::blend_write,
701 /*blend_read*/ blender::blend_read,
702};
703
704blender::Span<GreasePencilTimeModifierSegment> GreasePencilTimeModifierData::segments() const
705{
706 return {this->segments_array, this->segments_num};
707}
708
709blender::MutableSpan<GreasePencilTimeModifierSegment> GreasePencilTimeModifierData::segments()
710{
711 return {this->segments_array, this->segments_num};
712}
Low-level operations for curves.
Low-level operations for grease pencil.
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_SupportsMapping
@ eModifierTypeFlag_AcceptsGreasePencil
@ eModifierTypeFlag_EnableInEditmode
@ eModifierTypeFlag_SupportsEditmode
#define BLI_assert(a)
Definition BLI_assert.h:46
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
#define STRNCPY_UTF8(dst, src)
#define ELEM(...)
#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 BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
#define BLO_read_struct_array(reader, struct_name, array_size, ptr_p)
#define IFACE_(msgid)
#define DATA_(msgid)
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
#define DNA_struct_default_get(struct_name)
#define DNA_struct_default_alloc(struct_name)
GreasePencilTimeModifierMode
@ MOD_GREASE_PENCIL_TIME_MODE_FIX
@ MOD_GREASE_PENCIL_TIME_MODE_CHAIN
@ MOD_GREASE_PENCIL_TIME_MODE_PINGPONG
@ MOD_GREASE_PENCIL_TIME_MODE_NORMAL
@ MOD_GREASE_PENCIL_TIME_MODE_REVERSE
@ MOD_GREASE_PENCIL_TIME_KEEP_LOOP
@ MOD_GREASE_PENCIL_TIME_CUSTOM_RANGE
@ eModifierType_GreasePencilTime
GreasePencilTimeModifierSegmentMode
@ MOD_GREASE_PENCIL_TIME_SEG_MODE_NORMAL
@ MOD_GREASE_PENCIL_TIME_SEG_MODE_REVERSE
@ MOD_GREASE_PENCIL_TIME_SEG_MODE_PINGPONG
ModifierTypeInfo modifierType_GreasePencilTime
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 uiTemplateList(uiLayout *layout, const bContext *C, const char *listtype_name, const char *list_id, PointerRNA *dataptr, blender::StringRefNull propname, PointerRNA *active_dataptr, const char *active_propname, const char *item_dyntip_propname, int rows, int maxrows, int layout_type, int columns, enum uiTemplateListFlags flags)
@ UI_TEMPLATE_LIST_FLAG_NONE
@ UI_ITEM_R_NO_BG
void uiLayoutSetActive(uiLayout *layout, bool active)
void uiItemEnumO_string(uiLayout *layout, blender::StringRef name, int icon, blender::StringRefNull opname, blender::StringRefNull propname, const char *value_str)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
long long int int64_t
bool add_overwrite(const Key &key, const Value &value)
Definition BLI_map.hh:325
const Value & lookup(const Key &key) const
Definition BLI_map.hh:545
constexpr Span drop_front(int64_t n) const
Definition BLI_span.hh:171
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
constexpr const T & first() const
Definition BLI_span.hh:315
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr bool is_empty() const
Definition BLI_span.hh:260
const Map< FramesMapKeyT, GreasePencilFrame > & frames() const
Span< FramesMapKeyT > sorted_keys() const
Map< FramesMapKeyT, GreasePencilFrame > & frames_for_write()
void foreach_index(Fn &&fn) const
uint col
#define MEM_SAFE_FREE(v)
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
T floor(const T &a)
T ceil(const T &a)
void read_influence_data(BlendDataReader *reader, GreasePencilModifierInfluenceData *influence_data)
void init_influence_data(GreasePencilModifierInfluenceData *influence_data, const bool has_custom_curve)
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_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)
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
static void fill_scene_timeline(const GreasePencilTimeModifierData &tmd, const Scene &eval_scene, const Map< int, GreasePencilFrame > &frames, const Span< int > sorted_keys, const FrameRange scene_dst_range, Map< int, GreasePencilFrame > &dst_frames)
static void blend_write(BlendWriter *writer, const ID *, const ModifierData *md)
static void segment_list_item_draw(uiList *, const bContext *, uiLayout *layout, PointerRNA *, PointerRNA *itemptr, int, PointerRNA *, const char *, int, int)
static void fill_scene_range_fixed(const TimeMapping &mapping, const Map< int, GreasePencilFrame > &frames, const Span< int > sorted_keys, const int gp_src_frame, const FrameRange scene_dst_range, Map< int, GreasePencilFrame > &dst_frames)
static void init_data(ModifierData *md)
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
static void panel_draw(const bContext *C, Panel *panel)
static void fill_scene_range_chain(const TimeMapping &mapping, const Map< int, GreasePencilFrame > &frames, const Span< int > sorted_keys, const Span< GreasePencilTimeModifierSegment > segments, const FrameRange gp_src_range, const FrameRange scene_dst_range, Map< int, GreasePencilFrame > &dst_frames)
static void modify_geometry_set(ModifierData *md, const ModifierEvalContext *ctx, bke::GeometrySet *geometry_set)
static void calculate_repetitions(const TimeMapping &mapping, const FrameRange &gp_src, const FrameRange &scene_dst, int &r_start, int &r_count)
static void free_data(ModifierData *md)
static void panel_register(ARegionType *region_type)
static void fill_scene_range_forward(const TimeMapping &mapping, const Map< int, GreasePencilFrame > &frames, const Span< int > sorted_keys, const FrameRange gp_src_range, const FrameRange scene_dst_range, Map< int, GreasePencilFrame > &dst_frames)
static void fill_scene_range_ping_pong(const TimeMapping &mapping, const Map< int, GreasePencilFrame > &frames, const Span< int > sorted_keys, const FrameRange gp_src_range, const FrameRange scene_dst_range, Map< int, GreasePencilFrame > &dst_frames)
static void insert_keys_forward(const TimeMapping &mapping, const Map< int, GreasePencilFrame > &frames, const Span< int > sorted_keys, const FrameRange gp_src_range, const FrameRange gp_dst_range, Map< int, GreasePencilFrame > &dst_frames)
static void blend_read(BlendDataReader *reader, ModifierData *md)
static void fill_scene_range_reverse(const TimeMapping &mapping, const Map< int, GreasePencilFrame > &frames, const Span< int > sorted_keys, const FrameRange gp_src_range, const FrameRange scene_dst_range, Map< int, GreasePencilFrame > &dst_frames)
static IndexRange find_key_range(const Span< int > sorted_keys, const FrameRange &frame_range)
static void insert_keys_reverse(const TimeMapping &mapping, const Map< int, GreasePencilFrame > &frames, const Span< int > sorted_keys, const FrameRange gp_src_range, const FrameRange gp_dst_range, Map< int, GreasePencilFrame > &dst_frames)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
int RNA_enum_get(PointerRNA *ptr, const char *name)
GreasePencilTimeModifierSegment * segments_array
Definition DNA_ID.h:404
struct uiLayout * layout
struct RenderData r
FrameRange shift(const int n) const
FrameRange drop_back(const int n) const
FrameRange drop_front(const int n) const
int scene_frame_before_local_frame(const int local_frame) const
int local_frame_after_scene_frame(const int scene_frame) const
int local_frame_before_scene_frame(const int scene_frame) const
int scene_frame_after_local_frame(const int local_frame) const
float to_local_time(const float scene_frame) const
TimeMapping(const GreasePencilTimeModifierData &tmd)
float to_scene_time(const float local_frame) const
GreasePencil * get_grease_pencil_for_write()
PointerRNA op(wmOperatorType *ot, std::optional< blender::StringRef > name, int icon, wmOperatorCallContext context, eUI_Item_Flag flag)
PanelLayout panel_prop(const bContext *C, PointerRNA *open_prop_owner, blender::StringRefNull open_prop_name)
uiLayout & column(bool align)
uiLayout & row(bool align)
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)
char idname[BKE_ST_MAXNAME]
uiListDrawItemFunc draw_item
i
Definition text_draw.cc:230
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4227
bool WM_uilisttype_add(uiListType *ult)
uint8_t flag
Definition wm_window.cc:139