Blender V4.5
action_draw.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9/* System includes ----------------------------------------------------- */
10
11#include <cfloat>
12#include <cstdlib>
13#include <cstring>
14
15#include "BLI_listbase.h"
16#include "BLI_math_vector.h"
17#include "BLI_utildefines.h"
18
19/* Types --------------------------------------------------------------- */
20
21#include "DNA_anim_types.h"
22#include "DNA_modifier_types.h"
23#include "DNA_node_types.h"
24#include "DNA_object_types.h"
25#include "DNA_scene_types.h"
26#include "DNA_screen_types.h"
27
29#include "BKE_pointcache.h"
30
31#include "ANIM_action.hh"
32
33/* Everything from source (BIF, BDR, BSE) ------------------------------ */
34
35#include "GPU_immediate.hh"
36#include "GPU_matrix.hh"
37#include "GPU_state.hh"
38
39#include "UI_interface.hh"
40#include "UI_resources.hh"
41#include "UI_view2d.hh"
42
43#include "ED_anim_api.hh"
44#include "ED_keyframes_draw.hh"
45
46#include "MOD_nodes.hh"
47
48#include "action_intern.hh"
49
50using namespace blender;
51
52/* -------------------------------------------------------------------- */
55
57 bAnimContext *ac,
58 ARegion *region,
59 const ListBase /*bAnimListElem*/ &anim_data)
60{
61 bAnimListElem *ale;
62 View2D *v2d = &region->v2d;
63 /* need to do a view-sync here, so that the keys area doesn't jump around (it must copy this) */
64 UI_view2d_sync(nullptr, ac->area, v2d, V2D_LOCK_COPY);
65
66 const float channel_step = ANIM_UI_get_channel_step();
67 /* Loop through channels, and set up drawing depending on their type. */
68 { /* first pass: just the standard GL-drawing for backdrop + text */
69 size_t channel_index = 0;
70 float ymax = ANIM_UI_get_first_channel_top(v2d);
71
72 for (ale = static_cast<bAnimListElem *>(anim_data.first); ale;
73 ale = ale->next, ymax -= channel_step, channel_index++)
74 {
75 const float ymin = ymax - ANIM_UI_get_channel_height();
76
77 /* check if visible */
78 if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) ||
79 IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax))
80 {
81 /* draw all channels using standard channel-drawing API */
82 ANIM_channel_draw(ac, ale, ymin, ymax, channel_index);
83 }
84 }
85 }
86 { /* second pass: widgets */
87 uiBlock *block = UI_block_begin(C, region, __func__, blender::ui::EmbossType::Emboss);
88 size_t channel_index = 0;
89 float ymax = ANIM_UI_get_first_channel_top(v2d);
90
91 for (ale = static_cast<bAnimListElem *>(anim_data.first); ale;
92 ale = ale->next, ymax -= channel_step, channel_index++)
93 {
94 const float ymin = ymax - ANIM_UI_get_channel_height();
95
96 /* check if visible */
97 if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) ||
98 IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax))
99 {
100 /* draw all channels using standard channel-drawing API */
101 rctf channel_rect;
102 BLI_rctf_init(&channel_rect, 0, v2d->cur.xmax, ymin, ymax);
103 ANIM_channel_draw_widgets(C, ac, ale, block, &channel_rect, channel_index);
104 }
105 }
106
107 UI_block_end(C, block);
108 UI_block_draw(C, block);
109 }
110}
111
113
114/* -------------------------------------------------------------------- */
117
118/* extra padding for lengths (to go under scrollers) */
119#define EXTRA_SCROLL_PAD 100.0f
120
121/* Draw manually set intended playback frame ranges for actions. */
122static void draw_channel_action_ranges(ListBase *anim_data, View2D *v2d)
123{
124 /* Variables for coalescing the Y region of one action. */
125 bAction *cur_action = nullptr;
126 AnimData *cur_adt = nullptr;
127 float cur_ymax;
128
129 /* Walk through channels, grouping contiguous spans referencing the same action. */
131 const float ystep = ANIM_UI_get_channel_step();
132 float ymin = ymax - ystep;
133
134 for (bAnimListElem *ale = static_cast<bAnimListElem *>(anim_data->first); ale;
135 ale = ale->next, ymax = ymin, ymin -= ystep)
136 {
137 bAction *action = nullptr;
138 AnimData *adt = nullptr;
139
140 /* check if visible */
141 if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) ||
142 IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax))
143 {
144 /* check if anything to show for this channel */
145 if (ale->datatype != ALE_NONE) {
146 action = ANIM_channel_action_get(ale);
147
148 if (action) {
149 adt = ale->adt;
150 }
151 }
152 }
153
154 /* Extend the current region, or flush and restart. */
155 if (action != cur_action || adt != cur_adt) {
156 if (cur_action) {
157 ANIM_draw_action_framerange(cur_adt, cur_action, v2d, ymax, cur_ymax);
158 }
159
160 cur_action = action;
161 cur_adt = adt;
162 cur_ymax = ymax;
163 }
164 }
165
166 /* Flush the last region. */
167 if (cur_action) {
168 ANIM_draw_action_framerange(cur_adt, cur_action, v2d, ymax, cur_ymax);
169 }
170}
171
172static void draw_backdrops(bAnimContext *ac, ListBase &anim_data, View2D *v2d, uint pos)
173{
174 uchar col1[4], col2[4];
175 uchar col1a[4], col2a[4];
176 uchar col1b[4], col2b[4];
177 uchar col_summary[4];
178
179 /* get theme colors */
183
186
189
190 float ymax = ANIM_UI_get_first_channel_top(v2d);
191 const float channel_step = ANIM_UI_get_channel_step();
192 bAnimListElem *ale;
193 for (ale = static_cast<bAnimListElem *>(anim_data.first); ale;
194 ale = ale->next, ymax -= channel_step)
195 {
196 const float ymin = ymax - ANIM_UI_get_channel_height();
197
198 /* check if visible */
199 if (!(IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) ||
200 IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)))
201 {
202 continue;
203 }
205 int sel = 0;
206
207 /* determine if any need to draw channel */
208 if (ale->datatype == ALE_NONE) {
209 continue;
210 }
211 /* determine if channel is selected */
212 if (acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT)) {
214 }
215
217 switch (ale->type) {
218 case ANIMTYPE_SUMMARY: {
219 /* reddish color from NLA */
221 break;
222 }
224 case ANIMTYPE_SCENE:
225 case ANIMTYPE_OBJECT: {
226 immUniformColor3ubvAlpha(col1b, sel ? col1[3] : col1b[3]);
227 break;
228 }
231 case ANIMTYPE_DSSKEY:
232 case ANIMTYPE_DSWOR: {
233 immUniformColor3ubvAlpha(col2b, sel ? col1[3] : col2b[3]);
234 break;
235 }
236 case ANIMTYPE_GROUP:
237 immUniformColor4ubv(sel ? col1a : col2a);
238 break;
239 default: {
240 immUniformColor4ubv(sel ? col1 : col2);
241 }
242 }
243
244 /* draw region twice: firstly backdrop, then the current range */
245 immRectf(pos, v2d->cur.xmin, ymin, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymax);
246 }
247 else if (ac->datatype == ANIMCONT_GPENCIL) {
248 uchar *color;
249 switch (ale->type) {
250 case ANIMTYPE_SUMMARY:
251 color = col_summary;
252 break;
253
255 color = sel ? col1a : col2a;
256 break;
257
259 color = col2b;
260 color[3] = sel ? col1[3] : col2b[3];
261 break;
262
263 default:
264 color = sel ? col1 : col2;
265 break;
266 }
267
268 /* Color overlay on frames between the start/end frames. */
270 immRectf(pos, ac->scene->r.sfra, ymin, ac->scene->r.efra, ymax);
271
272 /* Color overlay outside the start/end frame range get a more transparent overlay. */
273 immUniformColor3ubvAlpha(color, std::min(255, color[3] / 2));
274 immRectf(pos, v2d->cur.xmin, ymin, ac->scene->r.sfra, ymax);
275 immRectf(pos, ac->scene->r.efra, ymin, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymax);
276 }
277 else if (ac->datatype == ANIMCONT_MASK) {
278 /* TODO: this is a copy of gpencil. */
279 uchar *color;
280 if (ale->type == ANIMTYPE_SUMMARY) {
281 color = col_summary;
282 }
283 else {
284 color = sel ? col1 : col2;
285 }
286
287 /* Color overlay on frames between the start/end frames. */
289 immRectf(pos, ac->scene->r.sfra, ymin, ac->scene->r.efra, ymax);
290
291 /* Color overlay outside the start/end frame range get a more transparent overlay. */
292 immUniformColor3ubvAlpha(color, std::min(255, color[3] / 2));
293 immRectf(pos, v2d->cur.xmin, ymin, ac->scene->r.sfra, ymax);
294 immRectf(pos, ac->scene->r.efra, ymin, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymax);
295 }
296
297 /* Alpha-over the channel color, if it's there. */
298 {
299 const bool show_group_colors = U.animation_flag & USER_ANIM_SHOW_CHANNEL_GROUP_COLORS;
300 uint8_t color[3];
301 if (show_group_colors && acf->get_channel_color && acf->get_channel_color(ale, color)) {
303 immRectf(pos, v2d->cur.xmin, ymin, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymax);
304 }
305 }
306 }
307}
308
310 View2D *v2d,
311 SpaceAction *saction,
312 ListBase &anim_data)
313{
314 /* Draw keyframes
315 * 1) Only channels that are visible in the Action Editor get drawn/evaluated.
316 * This is to try to optimize this for heavier data sets
317 * 2) Keyframes which are out of view horizontally are disregarded
318 */
319 int action_flag = saction->flag;
320 bDopeSheet *ads = &saction->ads;
321
322 if (saction->mode == SACTCONT_TIMELINE) {
324 }
325
326 const float channel_step = ANIM_UI_get_channel_step();
327 float ymax = ANIM_UI_get_first_channel_top(v2d);
328
330
331 const float scale_factor = ANIM_UI_get_keyframe_scale_factor();
332
333 bAnimListElem *ale;
334 for (ale = static_cast<bAnimListElem *>(anim_data.first); ale;
335 ale = ale->next, ymax -= channel_step)
336 {
337 const float ymin = ymax - ANIM_UI_get_channel_height();
338 float ycenter = (ymin + ymax) / 2.0f;
339
340 /* check if visible */
341 if (!(IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) ||
342 IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)))
343 {
344 continue;
345 }
346
347 /* check if anything to show for this channel */
348 if (ale->datatype == ALE_NONE) {
349 continue;
350 }
351
352 /* Add channels to list to draw later. */
353 switch (ale->datatype) {
354 case ALE_ALL:
356 draw_list, static_cast<bAnimContext *>(ale->data), ycenter, scale_factor, action_flag);
357 break;
358 case ALE_SCE:
359 ED_add_scene_channel(draw_list,
360 ads,
361 static_cast<Scene *>(ale->key_data),
362 ycenter,
363 scale_factor,
364 action_flag);
365 break;
366 case ALE_OB:
367 ED_add_object_channel(draw_list,
368 ads,
369 static_cast<Object *>(ale->key_data),
370 ycenter,
371 scale_factor,
372 action_flag);
373 break;
376 ac,
377 ale,
378 static_cast<bAction *>(ale->key_data),
379 ycenter,
380 scale_factor,
381 action_flag);
382 break;
383 case ALE_ACTION_SLOT:
385 ac,
386 ale,
387 static_cast<bAction *>(ale->key_data)->wrap(),
388 *static_cast<animrig::Slot *>(ale->data),
389 ycenter,
390 scale_factor,
391 action_flag);
392 break;
393 case ALE_ACT:
394 ED_add_action_channel(draw_list,
395 ale,
396 static_cast<bAction *>(ale->key_data),
397 ycenter,
398 scale_factor,
399 action_flag);
400 break;
401 case ALE_GROUP:
403 ale,
404 static_cast<bActionGroup *>(ale->data),
405 ycenter,
406 scale_factor,
407 action_flag);
408 break;
409 case ALE_FCURVE: {
410 ED_add_fcurve_channel(draw_list,
411 ale,
412 static_cast<FCurve *>(ale->key_data),
413 ycenter,
414 scale_factor,
415 action_flag);
416 break;
417 }
420 ads,
421 static_cast<const GreasePencilLayer *>(ale->data),
422 ycenter,
423 scale_factor,
424 action_flag);
425 break;
428 draw_list,
429 ads,
430 static_cast<const GreasePencilLayerTreeGroup *>(ale->data),
431 ycenter,
432 scale_factor,
433 action_flag);
434 break;
437 ac,
438 ale,
439 static_cast<const GreasePencil *>(ale->data),
440 ycenter,
441 scale_factor,
442 action_flag);
443 break;
444 case ALE_GPFRAME:
446 ads,
447 static_cast<bGPDlayer *>(ale->data),
448 ycenter,
449 scale_factor,
450 action_flag);
451 break;
452 case ALE_MASKLAY:
454 ads,
455 static_cast<MaskLayer *>(ale->data),
456 ycenter,
457 scale_factor,
458 action_flag);
459 break;
460 case ALE_NONE:
461 case ALE_NLASTRIP:
462 break;
463 }
464 }
465
466 /* Drawing happens in here. */
467 ED_channel_list_flush(draw_list, v2d);
468 ED_channel_list_free(draw_list);
469}
470
472 SpaceAction *saction,
473 ARegion *region,
474 ListBase *anim_data)
475{
476 View2D *v2d = &region->v2d;
477
478 /* Draw the manual frame ranges for actions in the background of the dope-sheet.
479 * The action editor has already drawn the range for its action so it's not needed. */
480 if (ac->datatype == ANIMCONT_DOPESHEET) {
481 draw_channel_action_ranges(anim_data, v2d);
482 }
483
484 /* Draw the background strips. */
487
489
491
492 /* first backdrop strips */
493 draw_backdrops(ac, *anim_data, v2d, pos);
494
496
497 /* black line marking 'current frame' for Time-Slide transform mode */
498 if (saction->flag & SACTION_MOVING) {
499 immUniformColor3f(0.0f, 0.0f, 0.0f);
500
503 immVertex2f(pos, saction->timeslide, v2d->cur.ymax);
504 immEnd();
505 }
507
508 draw_keyframes(ac, v2d, saction, *anim_data);
509
510 /* free temporary channels used for drawing */
511 ANIM_animdata_freelist(anim_data);
512}
513
515
516/* -------------------------------------------------------------------- */
519
520static bool timeline_cache_is_hidden_by_setting(const SpaceAction *saction, const PTCacheID *pid)
521{
522 switch (pid->type) {
524 if ((saction->cache_display & TIME_CACHE_SOFTBODY) == 0) {
525 return true;
526 }
527 break;
529 if ((saction->cache_display & TIME_CACHE_PARTICLES) == 0) {
530 return true;
531 }
532 break;
534 if ((saction->cache_display & TIME_CACHE_CLOTH) == 0) {
535 return true;
536 }
537 break;
540 if ((saction->cache_display & TIME_CACHE_SMOKE) == 0) {
541 return true;
542 }
543 break;
545 if ((saction->cache_display & TIME_CACHE_DYNAMICPAINT) == 0) {
546 return true;
547 }
548 break;
550 if ((saction->cache_display & TIME_CACHE_RIGIDBODY) == 0) {
551 return true;
552 }
553 break;
554 }
555 return false;
556}
557
558static void timeline_cache_color_get(PTCacheID *pid, float color[4])
559{
560 switch (pid->type) {
562 color[0] = 1.0;
563 color[1] = 0.4;
564 color[2] = 0.02;
565 color[3] = 0.1;
566 break;
568 color[0] = 1.0;
569 color[1] = 0.1;
570 color[2] = 0.02;
571 color[3] = 0.1;
572 break;
574 color[0] = 0.1;
575 color[1] = 0.1;
576 color[2] = 0.75;
577 color[3] = 0.1;
578 break;
581 color[0] = 0.2;
582 color[1] = 0.2;
583 color[2] = 0.2;
584 color[3] = 0.1;
585 break;
587 color[0] = 1.0;
588 color[1] = 0.1;
589 color[2] = 0.75;
590 color[3] = 0.1;
591 break;
593 color[0] = 1.0;
594 color[1] = 0.6;
595 color[2] = 0.0;
596 color[3] = 0.1;
597 break;
598 default:
599 color[0] = 1.0;
600 color[1] = 0.0;
601 color[2] = 1.0;
602 color[3] = 0.1;
603 BLI_assert(0);
604 break;
605 }
606}
607
609 float color[4],
610 float color_state[4])
611{
612 if (cache->flag & PTCACHE_BAKED) {
613 color[3] = color_state[3] = 1.0f;
614 }
615 else if (cache->flag & PTCACHE_OUTDATED) {
616 color[3] = color_state[3] = 0.7f;
617 mul_v3_fl(color_state, 0.5f);
618 }
619 else {
620 color[3] = color_state[3] = 0.7f;
621 }
622}
623
625 int search_start_frame,
626 int *r_segment_start,
627 int *r_segment_end)
628{
629 int offset = cache->startframe;
630 int current = search_start_frame;
631
632 /* Find segment start frame. */
633 while (true) {
634 if (current > cache->endframe) {
635 return false;
636 }
637 if (cache->cached_frames[current - offset]) {
638 *r_segment_start = current;
639 break;
640 }
641 current++;
642 }
643
644 /* Find segment end frame. */
645 while (true) {
646 if (current > cache->endframe) {
647 *r_segment_end = current - 1;
648 return true;
649 }
650 if (!cache->cached_frames[current - offset]) {
651 *r_segment_end = current - 1;
652 return true;
653 }
654 current++;
655 }
656}
657
659{
660 uint count = 0;
661
662 int current = cache->startframe;
663 int segment_start;
664 int segment_end;
665 while (timeline_cache_find_next_cached_segment(cache, current, &segment_start, &segment_end)) {
666 count++;
667 current = segment_end + 1;
668 }
669
670 return count;
671}
672
674{
675 uint segments_count = timeline_cache_segments_count(cache);
676 if (segments_count == 0) {
677 return;
678 }
679
680 immBeginAtMost(GPU_PRIM_TRIS, segments_count * 6);
681
682 int current = cache->startframe;
683 int segment_start;
684 int segment_end;
685 while (timeline_cache_find_next_cached_segment(cache, current, &segment_start, &segment_end)) {
686 immRectf_fast(pos_id, segment_start, 0, segment_end + 1.0f, 1.0f);
687 current = segment_end + 1;
688 }
689
690 immEnd();
691}
692
693static void timeline_cache_draw_single(PTCacheID *pid, float y_offset, float height, uint pos_id)
694{
697 GPU_matrix_scale_2f(1.0, height);
698
701
702 /* Mix in the background color to tone it down a bit. */
703 blender::ColorTheme4f background;
704 UI_GetThemeColor4fv(TH_BACK, background);
705
706 interp_v3_v3v3(color, color, background, 0.6f);
707
708 /* Highlight the frame range of the simulation. */
709 immUniform4fv("color1", color);
710 immUniform4fv("color2", color);
711 immRectf(pos_id, float(pid->cache->startframe), 0.0, float(pid->cache->endframe), 1.0);
712
713 /* Now show the cached frames on top. */
714 blender::ColorTheme4f color_state;
715 copy_v4_v4(color_state, color);
716
718
719 immUniform4fv("color1", color);
720 immUniform4fv("color2", color_state);
721
723
725}
726
731
733 const bool all_simulations_baked,
734 float *y_offset,
735 const float line_height,
736 const uint pos_id)
737{
738 if (cache_ranges.is_empty()) {
739 return;
740 }
741
742 bool has_bake = false;
743
744 for (const CacheRange &sim_range : cache_ranges) {
745 switch (sim_range.status) {
748 break;
750 has_bake = true;
751 break;
752 }
753 }
754
755 blender::Set<int> status_change_frames_set;
756 for (const CacheRange &sim_range : cache_ranges) {
757 status_change_frames_set.add(sim_range.frames.first());
758 status_change_frames_set.add(sim_range.frames.one_after_last());
759 }
760 blender::Vector<int> status_change_frames;
761 status_change_frames.extend(status_change_frames_set.begin(), status_change_frames_set.end());
762 std::sort(status_change_frames.begin(), status_change_frames.end());
763 const blender::OffsetIndices<int> frame_ranges = status_change_frames.as_span();
764
766 GPU_matrix_translate_2f(0.0, float(V2D_SCROLL_HANDLE_HEIGHT) + *y_offset);
767 GPU_matrix_scale_2f(1.0, line_height);
768
769 blender::ColorTheme4f base_color;
771 blender::ColorTheme4f invalid_color = base_color;
772 mul_v3_fl(invalid_color, 0.5f);
773 invalid_color.a *= 0.7f;
774 blender::ColorTheme4f valid_color = base_color;
775 valid_color.a *= 0.7f;
776 blender::ColorTheme4f baked_color = base_color;
777
778 float max_used_height = 1.0f;
779 for (const int range_i : frame_ranges.index_range()) {
780 const blender::IndexRange frame_range = frame_ranges[range_i];
781 const int start_frame = frame_range.first();
782 const int end_frame = frame_range.last();
783
784 bool has_bake_at_frame = false;
785 bool has_valid_at_frame = false;
786 bool has_invalid_at_frame = false;
787 for (const CacheRange &sim_range : cache_ranges) {
788 if (sim_range.frames.contains(start_frame)) {
789 switch (sim_range.status) {
791 has_invalid_at_frame = true;
792 break;
794 has_valid_at_frame = true;
795 break;
797 has_bake_at_frame = true;
798 break;
799 }
800 }
801 }
802 if (!(has_bake_at_frame || has_valid_at_frame || has_invalid_at_frame)) {
803 continue;
804 }
805
806 if (all_simulations_baked) {
807 immUniform4fv("color1", baked_color);
808 immUniform4fv("color2", baked_color);
810 immRectf_fast(pos_id, start_frame, 0, end_frame + 1.0f, 1.0f);
811 immEnd();
812 }
813 else {
814 if (has_valid_at_frame || has_invalid_at_frame) {
815 immUniform4fv("color1", valid_color);
816 immUniform4fv("color2", has_invalid_at_frame ? invalid_color : valid_color);
818 const float top = has_bake ? 2.0f : 1.0f;
819 immRectf_fast(pos_id, start_frame, 0.0f, end_frame + 1.0f, top);
820 immEnd();
821 max_used_height = top;
822 }
823 if (has_bake_at_frame) {
824 immUniform4fv("color1", baked_color);
825 immUniform4fv("color2", baked_color);
827 immRectf_fast(pos_id, start_frame, 0, end_frame + 1.0f, 1.0f);
828 immEnd();
829 }
830 }
831 }
833
834 *y_offset += max_used_height * 2;
835}
836
837void timeline_draw_cache(const SpaceAction *saction, const Object *ob, const Scene *scene)
838{
839 if ((saction->cache_display & TIME_CACHE_DISPLAY) == 0 || ob == nullptr) {
840 return;
841 }
842
843 ListBase pidlist;
844 BKE_ptcache_ids_from_object(&pidlist, const_cast<Object *>(ob), const_cast<Scene *>(scene), 0);
845
849
851
852 /* Iterate over point-caches on the active object, and draw each one's range. */
853 float y_offset = 0.0f;
854 const float cache_draw_height = 4.0f * UI_SCALE_FAC * U.pixelsize;
855
856 immUniform1i("size1", cache_draw_height * 2.0f);
857 immUniform1i("size2", cache_draw_height);
858
859 LISTBASE_FOREACH (PTCacheID *, pid, &pidlist) {
860 if (timeline_cache_is_hidden_by_setting(saction, pid)) {
861 continue;
862 }
863
864 if (pid->cache->cached_frames == nullptr) {
865 continue;
866 }
867
868 timeline_cache_draw_single(pid, y_offset, cache_draw_height, pos_id);
869
870 y_offset += cache_draw_height;
871 }
873 blender::Vector<CacheRange> cache_ranges;
874 bool all_simulations_baked = true;
876 if (md->type != eModifierType_Nodes) {
877 continue;
878 }
879 const NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
880 if (nmd->node_group == nullptr) {
881 continue;
882 }
883 if (!nmd->runtime->cache) {
884 continue;
885 }
886 if (nmd->node_group->nested_node_refs_num == 0) {
887 /* Skip when there are no bake nodes or simulations. */
888 continue;
889 }
890 const blender::bke::bake::ModifierCache &modifier_cache = *nmd->runtime->cache;
891 {
892 std::lock_guard lock{modifier_cache.mutex};
893 for (const auto item : modifier_cache.simulation_cache_by_id.items()) {
894 const blender::bke::bake::SimulationNodeCache &node_cache = *item.value;
895 if (node_cache.bake.frames.is_empty()) {
896 all_simulations_baked = false;
897 continue;
898 }
900 all_simulations_baked = false;
901 }
902 cache_ranges.append({node_cache.bake.frame_range(), node_cache.cache_status});
903 }
904 for (const auto item : modifier_cache.bake_cache_by_id.items()) {
905 const NodesModifierBake *bake = nmd->find_bake(item.key);
906 if (!bake) {
907 continue;
908 }
909 if (bake->bake_mode == NODES_MODIFIER_BAKE_MODE_STILL) {
910 continue;
911 }
912 const blender::bke::bake::BakeNodeCache &node_cache = *item.value;
913 if (node_cache.bake.frames.is_empty()) {
914 continue;
915 }
916 cache_ranges.append(
918 }
919 }
920 }
922 cache_ranges, all_simulations_baked, &y_offset, cache_draw_height, pos_id);
923 }
924
927
928 BLI_freelistN(&pidlist);
929}
930
Functions and classes to work with Actions.
#define PTCACHE_TYPE_SMOKE_HIGHRES
void BKE_ptcache_ids_from_object(struct ListBase *lb, struct Object *ob, struct Scene *scene, int duplis)
#define PTCACHE_TYPE_CLOTH
#define PTCACHE_TYPE_DYNAMICPAINT
#define PTCACHE_TYPE_PARTICLES
#define PTCACHE_TYPE_SOFTBODY
#define PTCACHE_TYPE_SMOKE_DOMAIN
#define PTCACHE_TYPE_RIGIDBODY
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void mul_v3_fl(float r[3], float f)
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
void BLI_rctf_init(struct rctf *rect, float xmin, float xmax, float ymin, float ymax)
Definition rct.cc:404
unsigned char uchar
unsigned int uint
#define IN_RANGE(a, b, c)
#define ELEM(...)
@ TIME_CACHE_PARTICLES
@ TIME_CACHE_RIGIDBODY
@ TIME_CACHE_DYNAMICPAINT
@ TIME_CACHE_SOFTBODY
@ TIME_CACHE_DISPLAY
@ TIME_CACHE_SIMULATION_NODES
@ TIME_CACHE_CLOTH
@ TIME_CACHE_SMOKE
@ SACTCONT_TIMELINE
@ SACTION_SHOW_INTERPOLATION
@ SACTION_SHOW_EXTREMES
@ SACTION_MOVING
@ eModifierType_Nodes
@ NODES_MODIFIER_BAKE_MODE_STILL
Object is a sort of wrapper for general info.
@ PTCACHE_BAKED
@ PTCACHE_OUTDATED
#define UI_SCALE_FAC
@ USER_ANIM_SHOW_CHANNEL_GROUP_COLORS
@ ANIMTYPE_SUMMARY
@ ANIMTYPE_GROUP
@ ANIMTYPE_ACTION_SLOT
@ ANIMTYPE_GREASE_PENCIL_DATABLOCK
@ ANIMTYPE_SCENE
@ ANIMTYPE_FILLACT_LAYERED
@ ANIMTYPE_FILLACTD
@ ANIMTYPE_OBJECT
@ ANIMTYPE_GREASE_PENCIL_LAYER_GROUP
@ ANIMTYPE_DSWOR
@ ANIMTYPE_DSSKEY
@ ALE_GREASE_PENCIL_GROUP
@ ALE_SCE
@ ALE_GREASE_PENCIL_CEL
@ ALE_GREASE_PENCIL_DATA
@ ALE_NONE
@ ALE_GPFRAME
@ ALE_FCURVE
@ ALE_NLASTRIP
@ ALE_ALL
@ ALE_ACT
@ ALE_ACTION_LAYERED
@ ALE_OB
@ ALE_GROUP
@ ALE_ACTION_SLOT
@ ALE_MASKLAY
@ ANIMCONT_MASK
@ ANIMCONT_SHAPEKEY
@ ANIMCONT_DOPESHEET
@ ANIMCONT_ACTION
@ ANIMCONT_GPENCIL
@ ACHANNEL_SETTING_SELECT
void immUniformColor4ubv(const unsigned char rgba[4])
void immEnd()
void immUnbindProgram()
void immVertex2f(uint attr_id, float x, float y)
void immUniformThemeColor(int color_id)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
void immUniform1i(const char *name, int x)
void immBeginAtMost(GPUPrimType, uint max_vertex_len)
void immUniformColor3ubvAlpha(const unsigned char rgb[3], unsigned char a)
GPUVertFormat * immVertexFormat()
void immUniformColor3f(float r, float g, float b)
void immUniform4fv(const char *name, const float data[4])
void immBegin(GPUPrimType, uint vertex_len)
void immRectf_fast(uint pos, float x1, float y1, float x2, float y2)
void immRectf(uint pos, float x1, float y1, float x2, float y2)
void GPU_matrix_scale_2f(float x, float y)
void GPU_matrix_push()
void GPU_matrix_pop()
void GPU_matrix_translate_2f(float x, float y)
@ GPU_PRIM_LINES
@ GPU_PRIM_TRIS
@ GPU_SHADER_2D_DIAG_STRIPES
@ GPU_SHADER_3D_UNIFORM_COLOR
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
void GPU_blend(eGPUBlend blend)
Definition gpu_state.cc:42
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, blender::StringRef name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
#define C
Definition RandGen.cpp:29
uiBlock * UI_block_begin(const bContext *C, ARegion *region, std::string name, blender::ui::EmbossType emboss)
void UI_block_draw(const bContext *C, uiBlock *block)
void UI_block_end(const bContext *C, uiBlock *block)
@ TH_SIMULATED_FRAMES
@ TH_BACK
@ TH_GROUP
@ TH_DOPESHEET_CHANNELSUBOB
@ TH_ANIM_ACTIVE
@ TH_SHADE2
@ TH_HILITE
@ TH_GROUP_ACTIVE
@ TH_DOPESHEET_CHANNELOB
void UI_GetThemeColor4fv(int colorid, float col[4])
void UI_GetThemeColor4ubv(int colorid, unsigned char col[4])
void UI_view2d_sync(bScreen *screen, ScrArea *area, View2D *v2dcur, int flag)
Definition view2d.cc:865
#define V2D_LOCK_COPY
Definition UI_view2d.hh:85
#define V2D_SCROLL_HANDLE_HEIGHT
Definition UI_view2d.hh:67
static void draw_backdrops(bAnimContext *ac, ListBase &anim_data, View2D *v2d, uint pos)
void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *region, const ListBase &anim_data)
static uint timeline_cache_segments_count(PointCache *cache)
static void timeline_cache_draw_cached_segments(PointCache *cache, uint pos_id)
void timeline_draw_cache(const SpaceAction *saction, const Object *ob, const Scene *scene)
static void timeline_cache_draw_single(PTCacheID *pid, float y_offset, float height, uint pos_id)
static void draw_channel_action_ranges(ListBase *anim_data, View2D *v2d)
void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region, ListBase *anim_data)
static void timeline_cache_draw_geometry_nodes(const blender::Span< CacheRange > cache_ranges, const bool all_simulations_baked, float *y_offset, const float line_height, const uint pos_id)
static void timeline_cache_modify_color_based_on_state(PointCache *cache, float color[4], float color_state[4])
static bool timeline_cache_is_hidden_by_setting(const SpaceAction *saction, const PTCacheID *pid)
static void draw_keyframes(bAnimContext *ac, View2D *v2d, SpaceAction *saction, ListBase &anim_data)
static void timeline_cache_color_get(PTCacheID *pid, float color[4])
static bool timeline_cache_find_next_cached_segment(PointCache *cache, int search_start_frame, int *r_segment_start, int *r_segment_end)
float ANIM_UI_get_channel_skip()
void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListElem *ale, uiBlock *block, const rctf *rect, size_t channel_index)
float ANIM_UI_get_keyframe_scale_factor()
void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc, size_t channel_index)
float ANIM_UI_get_channel_step()
float ANIM_UI_get_first_channel_top(View2D *v2d)
float ANIM_UI_get_channel_height()
bAction * ANIM_channel_action_get(const bAnimListElem *ale)
short ANIM_channel_setting_get(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting)
#define EXTRA_SCROLL_PAD
const bAnimChannelType * ANIM_channel_get_typeinfo(const bAnimListElem *ale)
void ANIM_animdata_freelist(ListBase *anim_data)
Definition anim_deps.cc:463
void ANIM_draw_action_framerange(AnimData *adt, bAction *action, View2D *v2d, float ymin, float ymax)
Definition anim_draw.cc:145
volatile int lock
#define U
ChannelStorageType a
Definition BLI_color.hh:93
constexpr int64_t first() const
constexpr int64_t last(const int64_t n=0) const
Iterator begin() const
Definition BLI_set.hh:480
Iterator end() const
Definition BLI_set.hh:490
bool add(const Key &key)
Definition BLI_set.hh:248
constexpr bool is_empty() const
Definition BLI_span.hh:260
void append(const T &value)
void extend(Span< T > array)
Span< T > as_span() const
uint pos
uint top
int count
void ED_add_fcurve_channel(ChannelDrawList *channel_list, bAnimListElem *ale, FCurve *fcu, float ypos, float yscale_fac, int saction_flag)
void ED_add_grease_pencil_layer_legacy_channel(ChannelDrawList *channel_list, bDopeSheet *ads, bGPDlayer *gpl, float ypos, float yscale_fac, int saction_flag)
ChannelDrawList * ED_channel_draw_list_create()
void ED_add_action_channel(ChannelDrawList *channel_list, bAnimListElem *ale, bAction *act, float ypos, float yscale_fac, int saction_flag)
void ED_add_grease_pencil_cels_channel(ChannelDrawList *channel_list, bDopeSheet *ads, const GreasePencilLayer *layer, const float ypos, const float yscale_fac, int saction_flag)
void ED_add_action_group_channel(ChannelDrawList *channel_list, bAnimListElem *ale, bActionGroup *agrp, float ypos, float yscale_fac, int saction_flag)
void ED_add_scene_channel(ChannelDrawList *channel_list, bDopeSheet *ads, Scene *sce, float ypos, float yscale_fac, int saction_flag)
void ED_channel_list_flush(ChannelDrawList *channel_list, View2D *v2d)
void ED_add_grease_pencil_datablock_channel(ChannelDrawList *channel_list, bAnimContext *ac, bAnimListElem *ale, const GreasePencil *grease_pencil, const float ypos, const float yscale_fac, int saction_flag)
void ED_add_grease_pencil_layer_group_channel(ChannelDrawList *channel_list, bDopeSheet *ads, const GreasePencilLayerTreeGroup *layer_group, const float ypos, const float yscale_fac, int saction_flag)
void ED_channel_list_free(ChannelDrawList *channel_list)
void ED_add_mask_layer_channel(ChannelDrawList *channel_list, bDopeSheet *ads, MaskLayer *masklay, float ypos, float yscale_fac, int saction_flag)
void ED_add_summary_channel(ChannelDrawList *channel_list, bAnimContext *ac, float ypos, float yscale_fac, int saction_flag)
void ED_add_object_channel(ChannelDrawList *channel_list, bDopeSheet *ads, Object *ob, float ypos, float yscale_fac, int saction_flag)
void ED_add_action_slot_channel(ChannelDrawList *channel_list, bAnimContext *ac, bAnimListElem *ale, animrig::Action &action, animrig::Slot &slot, const float ypos, const float yscale_fac, int saction_flag)
void ED_add_action_layered_channel(ChannelDrawList *channel_list, bAnimContext *ac, bAnimListElem *ale, bAction *action, const float ypos, const float yscale_fac, int saction_flag)
format
ColorTheme4< float > ColorTheme4f
Definition BLI_color.hh:292
blender::bke::bake::CacheStatus status
blender::IndexRange frames
void * first
struct bNodeTree * node_group
NodesModifierRuntimeHandle * runtime
ListBase modifiers
unsigned int type
struct PointCache * cache
struct RenderData r
bool(* has_setting)(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting)
bool(* get_channel_color)(const bAnimListElem *ale, uint8_t r_color[3])
eAnimCont_Types datatype
ScrArea * area
bAnimListElem * next
eAnim_ChannelType type
eAnim_KeyType datatype
int nested_node_refs_num
Map< int, std::unique_ptr< SimulationNodeCache > > simulation_cache_by_id
Map< int, std::unique_ptr< BakeNodeCache > > bake_cache_by_id
Vector< std::unique_ptr< FrameCache > > frames
float xmax
float xmin
float ymax
float ymin