Blender V5.0
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: {
220 /* Only draw the summary line backdrop when it is expanded. If the entire dope sheet is
221 * just one line, there is no need for any distinction between lines, and the red-ish
222 * color is only going to be a distraction. */
223 continue;
224 }
226 break;
227 }
229 case ANIMTYPE_SCENE:
230 case ANIMTYPE_OBJECT: {
231 immUniformColor3ubvAlpha(col1b, sel ? col1[3] : col1b[3]);
232 break;
233 }
236 case ANIMTYPE_DSSKEY:
237 case ANIMTYPE_DSWOR: {
238 immUniformColor3ubvAlpha(col2b, sel ? col1[3] : col2b[3]);
239 break;
240 }
241 case ANIMTYPE_GROUP:
242 immUniformColor4ubv(sel ? col1a : col2a);
243 break;
244 default: {
245 immUniformColor4ubv(sel ? col1 : col2);
246 }
247 }
248
249 /* draw region twice: firstly backdrop, then the current range */
250 immRectf(pos, v2d->cur.xmin, ymin, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymax);
251 }
252 else if (ac->datatype == ANIMCONT_GPENCIL) {
253 uchar *color;
254 switch (ale->type) {
255 case ANIMTYPE_SUMMARY:
256 color = col_summary;
257 break;
258
260 color = sel ? col1a : col2a;
261 break;
262
264 color = col2b;
265 color[3] = sel ? col1[3] : col2b[3];
266 break;
267
268 default:
269 color = sel ? col1 : col2;
270 break;
271 }
272
273 /* Color overlay on frames between the start/end frames. */
275 immRectf(pos, ac->scene->r.sfra, ymin, ac->scene->r.efra, ymax);
276
277 /* Color overlay outside the start/end frame range get a more transparent overlay. */
278 immUniformColor3ubvAlpha(color, std::min(255, color[3] / 2));
279 immRectf(pos, v2d->cur.xmin, ymin, ac->scene->r.sfra, ymax);
280 immRectf(pos, ac->scene->r.efra, ymin, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymax);
281 }
282 else if (ac->datatype == ANIMCONT_MASK) {
283 /* TODO: this is a copy of gpencil. */
284 uchar *color;
285 if (ale->type == ANIMTYPE_SUMMARY) {
286 color = col_summary;
287 }
288 else {
289 color = sel ? col1 : col2;
290 }
291
292 /* Color overlay on frames between the start/end frames. */
294 immRectf(pos, ac->scene->r.sfra, ymin, ac->scene->r.efra, ymax);
295
296 /* Color overlay outside the start/end frame range get a more transparent overlay. */
297 immUniformColor3ubvAlpha(color, std::min(255, color[3] / 2));
298 immRectf(pos, v2d->cur.xmin, ymin, ac->scene->r.sfra, ymax);
299 immRectf(pos, ac->scene->r.efra, ymin, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymax);
300 }
301
302 /* Alpha-over the channel color, if it's there. */
303 {
304 const bool show_group_colors = U.animation_flag & USER_ANIM_SHOW_CHANNEL_GROUP_COLORS;
305 uint8_t color[3];
306 if (show_group_colors && acf->get_channel_color && acf->get_channel_color(ale, color)) {
308 immRectf(pos, v2d->cur.xmin, ymin, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymax);
309 }
310 }
311 }
312}
313
315 View2D *v2d,
316 SpaceAction *saction,
317 ListBase &anim_data)
318{
319 /* Draw keyframes
320 * 1) Only channels that are visible in the Action Editor get drawn/evaluated.
321 * This is to try to optimize this for heavier data sets
322 * 2) Keyframes which are out of view horizontally are disregarded
323 */
324 int action_flag = saction->flag;
325 bDopeSheet *ads = &saction->ads;
326
327 if (saction->mode == SACTCONT_TIMELINE) {
328 action_flag &= ~SACTION_SHOW_INTERPOLATION;
329 }
330
331 const float channel_step = ANIM_UI_get_channel_step();
332 float ymax = ANIM_UI_get_first_channel_top(v2d);
333
335
336 const float scale_factor = ANIM_UI_get_keyframe_scale_factor();
337
338 bAnimListElem *ale;
339 for (ale = static_cast<bAnimListElem *>(anim_data.first); ale;
340 ale = ale->next, ymax -= channel_step)
341 {
342 const float ymin = ymax - ANIM_UI_get_channel_height();
343 float ycenter = (ymin + ymax) / 2.0f;
344
345 /* check if visible */
346 if (!(IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) ||
347 IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)))
348 {
349 continue;
350 }
351
352 /* check if anything to show for this channel */
353 if (ale->datatype == ALE_NONE) {
354 continue;
355 }
356
357 /* Add channels to list to draw later. */
358 switch (ale->datatype) {
359 case ALE_ALL:
361 draw_list, static_cast<bAnimContext *>(ale->data), ycenter, scale_factor, action_flag);
362 break;
363 case ALE_SCE:
364 ED_add_scene_channel(draw_list,
365 ads,
366 static_cast<Scene *>(ale->key_data),
367 ycenter,
368 scale_factor,
369 action_flag);
370 break;
371 case ALE_OB:
372 ED_add_object_channel(draw_list,
373 ads,
374 static_cast<Object *>(ale->key_data),
375 ycenter,
376 scale_factor,
377 action_flag);
378 break;
381 ac,
382 ale,
383 static_cast<bAction *>(ale->key_data),
384 ycenter,
385 scale_factor,
386 action_flag);
387 break;
388 case ALE_ACTION_SLOT:
390 ac,
391 ale,
392 static_cast<bAction *>(ale->key_data)->wrap(),
393 *static_cast<animrig::Slot *>(ale->data),
394 ycenter,
395 scale_factor,
396 action_flag);
397 break;
398 case ALE_ACT:
399 ED_add_action_channel(draw_list,
400 ale,
401 static_cast<bAction *>(ale->key_data),
402 ycenter,
403 scale_factor,
404 action_flag);
405 break;
406 case ALE_GROUP:
408 ale,
409 static_cast<bActionGroup *>(ale->data),
410 ycenter,
411 scale_factor,
412 action_flag);
413 break;
414 case ALE_FCURVE: {
415 ED_add_fcurve_channel(draw_list,
416 ale,
417 static_cast<FCurve *>(ale->key_data),
418 ycenter,
419 scale_factor,
420 action_flag);
421 break;
422 }
425 ads,
426 static_cast<const GreasePencilLayer *>(ale->data),
427 ycenter,
428 scale_factor,
429 action_flag);
430 break;
433 draw_list,
434 ads,
435 static_cast<const GreasePencilLayerTreeGroup *>(ale->data),
436 ycenter,
437 scale_factor,
438 action_flag);
439 break;
442 ac,
443 ale,
444 static_cast<const GreasePencil *>(ale->data),
445 ycenter,
446 scale_factor,
447 action_flag);
448 break;
449 case ALE_GPFRAME:
451 ads,
452 static_cast<bGPDlayer *>(ale->data),
453 ycenter,
454 scale_factor,
455 action_flag);
456 break;
457 case ALE_MASKLAY:
459 ads,
460 static_cast<MaskLayer *>(ale->data),
461 ycenter,
462 scale_factor,
463 action_flag);
464 break;
465 case ALE_NONE:
466 case ALE_NLASTRIP:
467 break;
468 }
469 }
470
471 /* Drawing happens in here. */
472 ED_channel_list_flush(draw_list, v2d);
473 ED_channel_list_free(draw_list);
474}
475
477 SpaceAction *saction,
478 ARegion *region,
479 ListBase *anim_data)
480{
481 View2D *v2d = &region->v2d;
482
483 /* Draw the manual frame ranges for actions in the background of the dope-sheet.
484 * The action editor has already drawn the range for its action so it's not needed. */
485 if (ac->datatype == ANIMCONT_DOPESHEET) {
486 draw_channel_action_ranges(anim_data, v2d);
487 }
488
489 /* Draw the background strips. */
491 uint pos = GPU_vertformat_attr_add(format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
492
494
496
497 /* first backdrop strips */
498 draw_backdrops(ac, *anim_data, v2d, pos);
499
501
502 /* black line marking 'current frame' for Time-Slide transform mode */
503 if (saction->flag & SACTION_MOVING) {
504 immUniformColor3f(0.0f, 0.0f, 0.0f);
505
508 immVertex2f(pos, saction->timeslide, v2d->cur.ymax);
509 immEnd();
510 }
512
513 draw_keyframes(ac, v2d, saction, *anim_data);
514
515 /* free temporary channels used for drawing */
516 ANIM_animdata_freelist(anim_data);
517}
518
520
521/* -------------------------------------------------------------------- */
524
525static bool timeline_cache_is_hidden_by_setting(const SpaceAction *saction, const PTCacheID *pid)
526{
527 switch (pid->type) {
529 if ((saction->cache_display & TIME_CACHE_SOFTBODY) == 0) {
530 return true;
531 }
532 break;
534 if ((saction->cache_display & TIME_CACHE_PARTICLES) == 0) {
535 return true;
536 }
537 break;
539 if ((saction->cache_display & TIME_CACHE_CLOTH) == 0) {
540 return true;
541 }
542 break;
545 if ((saction->cache_display & TIME_CACHE_SMOKE) == 0) {
546 return true;
547 }
548 break;
550 if ((saction->cache_display & TIME_CACHE_DYNAMICPAINT) == 0) {
551 return true;
552 }
553 break;
555 if ((saction->cache_display & TIME_CACHE_RIGIDBODY) == 0) {
556 return true;
557 }
558 break;
559 }
560 return false;
561}
562
563static void timeline_cache_color_get(PTCacheID *pid, float color[4])
564{
565 switch (pid->type) {
567 color[0] = 1.0;
568 color[1] = 0.4;
569 color[2] = 0.02;
570 color[3] = 0.1;
571 break;
573 color[0] = 1.0;
574 color[1] = 0.1;
575 color[2] = 0.02;
576 color[3] = 0.1;
577 break;
579 color[0] = 0.1;
580 color[1] = 0.1;
581 color[2] = 0.75;
582 color[3] = 0.1;
583 break;
586 color[0] = 0.2;
587 color[1] = 0.2;
588 color[2] = 0.2;
589 color[3] = 0.1;
590 break;
592 color[0] = 1.0;
593 color[1] = 0.1;
594 color[2] = 0.75;
595 color[3] = 0.1;
596 break;
598 color[0] = 1.0;
599 color[1] = 0.6;
600 color[2] = 0.0;
601 color[3] = 0.1;
602 break;
603 default:
604 color[0] = 1.0;
605 color[1] = 0.0;
606 color[2] = 1.0;
607 color[3] = 0.1;
608 BLI_assert(0);
609 break;
610 }
611}
612
614 float color[4],
615 float color_state[4])
616{
617 if (cache->flag & PTCACHE_BAKED) {
618 color[3] = color_state[3] = 1.0f;
619 }
620 else if (cache->flag & PTCACHE_OUTDATED) {
621 color[3] = color_state[3] = 0.7f;
622 mul_v3_fl(color_state, 0.5f);
623 }
624 else {
625 color[3] = color_state[3] = 0.7f;
626 }
627}
628
630 int search_start_frame,
631 int *r_segment_start,
632 int *r_segment_end)
633{
634 int offset = cache->startframe;
635 int current = search_start_frame;
636
637 /* Find segment start frame. */
638 while (true) {
639 if (current > cache->endframe) {
640 return false;
641 }
642 if (cache->cached_frames[current - offset]) {
643 *r_segment_start = current;
644 break;
645 }
646 current++;
647 }
648
649 /* Find segment end frame. */
650 while (true) {
651 if (current > cache->endframe) {
652 *r_segment_end = current - 1;
653 return true;
654 }
655 if (!cache->cached_frames[current - offset]) {
656 *r_segment_end = current - 1;
657 return true;
658 }
659 current++;
660 }
661}
662
664{
665 uint count = 0;
666
667 int current = cache->startframe;
668 int segment_start;
669 int segment_end;
670 while (timeline_cache_find_next_cached_segment(cache, current, &segment_start, &segment_end)) {
671 count++;
672 current = segment_end + 1;
673 }
674
675 return count;
676}
677
679{
680 uint segments_count = timeline_cache_segments_count(cache);
681 if (segments_count == 0) {
682 return;
683 }
684
685 immBeginAtMost(GPU_PRIM_TRIS, segments_count * 6);
686
687 int current = cache->startframe;
688 int segment_start;
689 int segment_end;
690 while (timeline_cache_find_next_cached_segment(cache, current, &segment_start, &segment_end)) {
691 immRectf_fast(pos_id, segment_start, 0, segment_end + 1.0f, 1.0f);
692 current = segment_end + 1;
693 }
694
695 immEnd();
696}
697
698static void timeline_cache_draw_single(PTCacheID *pid, float y_offset, float height, uint pos_id)
699{
702 GPU_matrix_scale_2f(1.0, height);
703
706
707 /* Mix in the background color to tone it down a bit. */
708 blender::ColorTheme4f background;
709 UI_GetThemeColor4fv(TH_BACK, background);
710
711 interp_v3_v3v3(color, color, background, 0.6f);
712
713 /* Highlight the frame range of the simulation. */
714 immUniform4fv("color1", color);
715 immUniform4fv("color2", color);
716 immRectf(pos_id, float(pid->cache->startframe), 0.0, float(pid->cache->endframe), 1.0);
717
718 /* Now show the cached frames on top. */
719 blender::ColorTheme4f color_state;
720 copy_v4_v4(color_state, color);
721
723
724 immUniform4fv("color1", color);
725 immUniform4fv("color2", color_state);
726
728
730}
731
736
738 const bool all_simulations_baked,
739 float *y_offset,
740 const float line_height,
741 const uint pos_id)
742{
743 if (cache_ranges.is_empty()) {
744 return;
745 }
746
747 bool has_bake = false;
748
749 for (const CacheRange &sim_range : cache_ranges) {
750 switch (sim_range.status) {
753 break;
755 has_bake = true;
756 break;
757 }
758 }
759
760 blender::Set<int> status_change_frames_set;
761 for (const CacheRange &sim_range : cache_ranges) {
762 status_change_frames_set.add(sim_range.frames.first());
763 status_change_frames_set.add(sim_range.frames.one_after_last());
764 }
765 blender::Vector<int> status_change_frames;
766 status_change_frames.extend(status_change_frames_set.begin(), status_change_frames_set.end());
767 std::sort(status_change_frames.begin(), status_change_frames.end());
768 const blender::OffsetIndices<int> frame_ranges = status_change_frames.as_span();
769
771 GPU_matrix_translate_2f(0.0, float(V2D_SCROLL_HANDLE_HEIGHT) + *y_offset);
772 GPU_matrix_scale_2f(1.0, line_height);
773
774 blender::ColorTheme4f base_color;
776 blender::ColorTheme4f invalid_color = base_color;
777 mul_v3_fl(invalid_color, 0.5f);
778 invalid_color.a *= 0.7f;
779 blender::ColorTheme4f valid_color = base_color;
780 valid_color.a *= 0.7f;
781 blender::ColorTheme4f baked_color = base_color;
782
783 float max_used_height = 1.0f;
784 for (const int range_i : frame_ranges.index_range()) {
785 const blender::IndexRange frame_range = frame_ranges[range_i];
786 const int start_frame = frame_range.first();
787 const int end_frame = frame_range.last();
788
789 bool has_bake_at_frame = false;
790 bool has_valid_at_frame = false;
791 bool has_invalid_at_frame = false;
792 for (const CacheRange &sim_range : cache_ranges) {
793 if (sim_range.frames.contains(start_frame)) {
794 switch (sim_range.status) {
796 has_invalid_at_frame = true;
797 break;
799 has_valid_at_frame = true;
800 break;
802 has_bake_at_frame = true;
803 break;
804 }
805 }
806 }
807 if (!(has_bake_at_frame || has_valid_at_frame || has_invalid_at_frame)) {
808 continue;
809 }
810
811 if (all_simulations_baked) {
812 immUniform4fv("color1", baked_color);
813 immUniform4fv("color2", baked_color);
815 immRectf_fast(pos_id, start_frame, 0, end_frame + 1.0f, 1.0f);
816 immEnd();
817 }
818 else {
819 if (has_valid_at_frame || has_invalid_at_frame) {
820 immUniform4fv("color1", valid_color);
821 immUniform4fv("color2", has_invalid_at_frame ? invalid_color : valid_color);
823 const float top = has_bake ? 2.0f : 1.0f;
824 immRectf_fast(pos_id, start_frame, 0.0f, end_frame + 1.0f, top);
825 immEnd();
826 max_used_height = top;
827 }
828 if (has_bake_at_frame) {
829 immUniform4fv("color1", baked_color);
830 immUniform4fv("color2", baked_color);
832 immRectf_fast(pos_id, start_frame, 0, end_frame + 1.0f, 1.0f);
833 immEnd();
834 }
835 }
836 }
838
839 *y_offset += max_used_height * 2;
840}
841
842void timeline_draw_cache(const SpaceAction *saction, const Object *ob, const Scene *scene)
843{
844 if ((saction->cache_display & TIME_CACHE_DISPLAY) == 0 || ob == nullptr) {
845 return;
846 }
847
848 ListBase pidlist;
849 BKE_ptcache_ids_from_object(&pidlist, const_cast<Object *>(ob), const_cast<Scene *>(scene), 0);
850
852 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
854
856
857 /* Iterate over point-caches on the active object, and draw each one's range. */
858 float y_offset = 0.0f;
859 const float cache_draw_height = 4.0f * UI_SCALE_FAC * U.pixelsize;
860
861 immUniform1i("size1", cache_draw_height * 2.0f);
862 immUniform1i("size2", cache_draw_height);
863
864 LISTBASE_FOREACH (PTCacheID *, pid, &pidlist) {
865 if (timeline_cache_is_hidden_by_setting(saction, pid)) {
866 continue;
867 }
868
869 if (pid->cache->cached_frames == nullptr) {
870 continue;
871 }
872
873 timeline_cache_draw_single(pid, y_offset, cache_draw_height, pos_id);
874
875 y_offset += cache_draw_height;
876 }
878 blender::Vector<CacheRange> cache_ranges;
879 bool all_simulations_baked = true;
881 if (md->type != eModifierType_Nodes) {
882 continue;
883 }
884 const NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
885 if (nmd->node_group == nullptr) {
886 continue;
887 }
888 if (!nmd->runtime->cache) {
889 continue;
890 }
891 if (nmd->node_group->nested_node_refs_num == 0) {
892 /* Skip when there are no bake nodes or simulations. */
893 continue;
894 }
895 const blender::bke::bake::ModifierCache &modifier_cache = *nmd->runtime->cache;
896 {
897 std::lock_guard lock{modifier_cache.mutex};
898 for (const auto item : modifier_cache.simulation_cache_by_id.items()) {
899 const blender::bke::bake::SimulationNodeCache &node_cache = *item.value;
900 if (node_cache.bake.frames.is_empty()) {
901 all_simulations_baked = false;
902 continue;
903 }
905 all_simulations_baked = false;
906 }
907 cache_ranges.append({node_cache.bake.frame_range(), node_cache.cache_status});
908 }
909 for (const auto item : modifier_cache.bake_cache_by_id.items()) {
910 const NodesModifierBake *bake = nmd->find_bake(item.key);
911 if (!bake) {
912 continue;
913 }
914 if (bake->bake_mode == NODES_MODIFIER_BAKE_MODE_STILL) {
915 continue;
916 }
917 const blender::bke::bake::BakeNodeCache &node_cache = *item.value;
918 if (node_cache.bake.frames.is_empty()) {
919 continue;
920 }
921 cache_ranges.append(
923 }
924 }
925 }
927 cache_ranges, all_simulations_baked, &y_offset, cache_draw_height, pos_id);
928 }
929
932
933 BLI_freelistN(&pidlist);
934}
935
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_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_EXPAND
@ ACHANNEL_SETTING_SELECT
void immUniformColor4ubv(const unsigned char rgba[4])
void immEnd()
void immUnbindProgram()
void immBindBuiltinProgram(GPUBuiltinShader shader_id)
void immVertex2f(uint attr_id, float x, float y)
void immUniformThemeColor(int color_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(GPUBlend blend)
Definition gpu_state.cc:42
uint GPU_vertformat_attr_add(GPUVertFormat *format, blender::StringRef name, blender::gpu::VertAttrType type)
#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_CHANNEL
@ TH_CHANNEL_SELECT
@ 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:207
volatile int lock
#define U
ChannelStorageType a
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
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