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