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