Blender V4.5
nla_draw.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009 Blender Authors, Joshua Leung. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cfloat>
10#include <cmath>
11#include <cstdio>
12#include <cstdlib>
13#include <cstring>
14
15#include "DNA_anim_types.h"
16#include "DNA_screen_types.h"
17#include "DNA_space_types.h"
18
19#include "BLI_bounds_types.hh"
20#include "BLI_listbase.h"
21#include "BLI_string.h"
22#include "BLI_utildefines.h"
23
24#include "BLT_translation.hh"
25
26#include "BKE_fcurve.hh"
27#include "BKE_nla.hh"
28
29#include "ED_anim_api.hh"
30#include "ED_keyframes_draw.hh"
32
33#include "GPU_immediate.hh"
34#include "GPU_immediate_util.hh"
35#include "GPU_state.hh"
36
37#include "WM_types.hh"
38
39#include "UI_interface.hh"
40#include "UI_resources.hh"
41#include "UI_view2d.hh"
42
43#include "nla_intern.hh" /* own include */
44#include "nla_private.h"
45
46using namespace blender;
47
48/* *********************************************** */
49/* Strips */
50
51/* Action-Line ---------------------- */
52
53void nla_action_get_color(AnimData *adt, bAction *act, float color[4])
54{
55 if (adt && (adt->flag & ADT_NLA_EDIT_ON)) {
56 /* greenish color (same as tweaking strip) */
58 }
59 else {
60 if (act) {
61 /* reddish color - same as dope-sheet summary */
63 }
64 else {
65 /* grayish-red color */
67 }
68 }
69
70 /* when an NLA track is tagged "solo", action doesn't contribute,
71 * so shouldn't be as prominent */
72 if (adt && (adt->flag & ADT_NLA_SOLO_TRACK)) {
73 color[3] *= 0.15f;
74 }
75}
76
77/* draw the keyframes in the specified Action */
79 View2D *v2d, AnimData *adt, bAction *act, float y, float ymin, float ymax)
80{
81 if (act == nullptr) {
82 return;
83 }
84
85 /* get a list of the keyframes with NLA-scaling applied */
86 AnimKeylist *keylist = ED_keylist_create();
87 action_to_keylist(adt, act, keylist, 0, {v2d->cur.xmin, v2d->cur.xmax});
88
89 if (ED_keylist_is_empty(keylist)) {
90 ED_keylist_free(keylist);
91 return;
92 }
93
94 /* draw a darkened region behind the strips
95 * - get and reset the background color, this time without the alpha to stand out better
96 * (amplified alpha is used instead, but clamped to avoid 100% opacity)
97 */
98 float color[4];
99 nla_action_get_color(adt, act, color);
100 color[3] = min_ff(0.7f, color[3] * 2.5f);
101
104
106
108
109 /* - draw a rect from the first to the last frame (no extra overlaps for now)
110 * that is slightly stumpier than the track background (hardcoded 2-units here)
111 */
112
113 Bounds<float> frame_range;
114 ED_keylist_all_keys_frame_range(keylist, &frame_range);
115 immRectf(pos_id, frame_range.min, ymin + 2, frame_range.max, ymax - 2);
117
118 /* Count keys before drawing. */
119 const ListBase *keys = ED_keylist_listbase(keylist);
120 uint key_len = BLI_listbase_count(keys);
121
122 if (key_len > 0) {
124 KeyframeShaderBindings sh_bindings;
126 sh_bindings.size_id = GPU_vertformat_attr_add(
127 format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
128 sh_bindings.color_id = GPU_vertformat_attr_add(
131 format, "outlineColor", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
132 sh_bindings.flags_id = GPU_vertformat_attr_add(
133 format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT);
134
137 immUniform1f("outline_scale", 1.0f);
138 immUniform2f("ViewportSize", BLI_rcti_size_x(&v2d->mask) + 1, BLI_rcti_size_y(&v2d->mask) + 1);
139 immBegin(GPU_PRIM_POINTS, key_len);
140
141 /* - disregard the selection status of keyframes so they draw a certain way
142 * - size is 6.0f which is smaller than the editable keyframes, so that there is a distinction
143 */
144 LISTBASE_FOREACH (const ActKeyColumn *, ak, keys) {
145 draw_keyframe_shape(ak->cfra,
146 y,
147 6.0f,
148 false,
149 ak->key_type,
151 1.0f,
152 &sh_bindings,
155 }
156
157 immEnd();
160 }
161
162 /* free icons */
163 ED_keylist_free(keylist);
164}
165
166/* Strip Markers ------------------------ */
167
168/* Markers inside an action strip */
170 NlaStrip *strip, float yminc, float ymaxc, int shade, const bool dashed)
171{
172 const bAction *act = strip->act;
173
174 if (ELEM(nullptr, act, act->markers.first)) {
175 return;
176 }
177
178 const uint shdr_pos = GPU_vertformat_attr_add(
180 if (dashed) {
182
183 float viewport_size[4];
184 GPU_viewport_size_get_f(viewport_size);
186 "viewport_size", viewport_size[2] / UI_SCALE_FAC, viewport_size[3] / UI_SCALE_FAC);
187
188 immUniform1i("colors_len", 0); /* "simple" mode */
189 immUniform1f("dash_width", 6.0f);
190 immUniform1f("udash_factor", 0.5f);
191 }
192 else {
194 }
196
198 LISTBASE_FOREACH (TimeMarker *, marker, &act->markers) {
199 if ((marker->frame > strip->actstart) && (marker->frame < strip->actend)) {
200 float frame = nlastrip_get_frame(strip, marker->frame, NLATIME_CONVERT_MAP);
201
202 /* just a simple line for now */
203 /* XXX: draw a triangle instead... */
204 immVertex2f(shdr_pos, frame, yminc + 1);
205 immVertex2f(shdr_pos, frame, ymaxc - 1);
206 }
207 }
208 immEnd();
209
211}
212
213/* Markers inside a NLA-Strip */
214static void nla_strip_draw_markers(NlaStrip *strip, float yminc, float ymaxc)
215{
216 GPU_line_width(2.0f);
217
218 if (strip->type == NLASTRIP_TYPE_CLIP) {
219 /* try not to be too conspicuous, while being visible enough when transforming */
220 int shade = (strip->flag & NLASTRIP_FLAG_SELECT) ? -60 : -40;
221
222 /* just draw the markers in this clip */
223 nla_actionclip_draw_markers(strip, yminc, ymaxc, shade, true);
224 }
225 else if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
226 /* just a solid color, so that it is very easy to spot */
227 int shade = 20;
228 /* draw the markers in the first level of strips only (if they are actions) */
229 LISTBASE_FOREACH (NlaStrip *, nls, &strip->strips) {
230 if (nls->type == NLASTRIP_TYPE_CLIP) {
231 nla_actionclip_draw_markers(nls, yminc, ymaxc, shade, false);
232 }
233 }
234 }
235
236 GPU_line_width(1.0f);
237}
238
239/* Strips (Proper) ---------------------- */
240
241/* Get colors for drawing NLA Strips. */
242static void nla_strip_get_color_inside(AnimData *adt, NlaStrip *strip, float color[3])
243{
244 const bool is_selected = strip->flag & NLASTRIP_FLAG_SELECT;
245 switch (strip->type) {
247 /* Action Strip. */
248 if (adt && (adt->flag & ADT_NLA_EDIT_ON) && (adt->actstrip == strip)) {
249 /* Active strip tweak - tweak theme is applied only to active edit strip,
250 * not linked-duplicates.
251 */
253 break;
254 }
255
256 if (strip->flag & NLASTRIP_FLAG_TWEAKUSER) {
257 /* Non-active strip tweak - display warning theme
258 * for non active linked-duplicates.
259 */
261 break;
262 }
263 if (strip->flag & NLASTRIP_FLAG_SELECT) {
264 /* selected. */
266 break;
267 }
268
269 /* unselected - use standard strip theme. */
271 break;
272
274 /* Meta Strip. */
276 break;
278 /* Transition Strip. */
280 break;
281 }
283 /* Sound Strip. */
285 break;
286 default: {
287 /* default to unselected theme. */
289 } break;
290 }
291}
292
293/* helper call for drawing influence/time control curves for a given NLA-strip */
294static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc, uint pos)
295{
296 const float yheight = ymaxc - yminc;
297
298 /* draw with AA'd line */
299 GPU_line_smooth(true);
301
302 /* Fully opaque line on selected strips. */
303 if (strip->flag & NLASTRIP_FLAG_SELECT) {
304 /* TODO: Use theme setting. */
305 immUniformColor3f(1.0f, 1.0f, 1.0f);
306 }
307 else {
308 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
309 }
310
311 /* influence -------------------------- */
312 if (strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) {
313 const FCurve *fcu = BKE_fcurve_find(&strip->fcurves, "influence", 0);
314
315 /* plot the curve (over the strip's main region) */
316 if (fcu) {
317 immBegin(GPU_PRIM_LINE_STRIP, abs(int(strip->end - strip->start) + 1));
318
319 /* sample at 1 frame intervals, and draw
320 * - min y-val is yminc, max is y-maxc, so clamp in those regions
321 */
322 for (float cfra = strip->start; cfra <= strip->end; cfra += 1.0f) {
323 float y = evaluate_fcurve(fcu, cfra); /* assume this to be in 0-1 range */
324 CLAMP(y, 0.0f, 1.0f);
325 immVertex2f(pos, cfra, ((y * yheight) + yminc));
326 }
327
328 immEnd();
329 }
330 }
331 else {
332 /* use blend in/out values only if both aren't zero */
333 if ((IS_EQF(strip->blendin, 0.0f) && IS_EQF(strip->blendout, 0.0f)) == 0) {
335
336 /* start of strip - if no blendin, start straight at 1,
337 * otherwise from 0 to 1 over blendin frames */
338 if (IS_EQF(strip->blendin, 0.0f) == 0) {
339 immVertex2f(pos, strip->start, yminc);
340 immVertex2f(pos, strip->start + strip->blendin, ymaxc);
341 }
342 else {
343 immVertex2f(pos, strip->start, ymaxc);
344 }
345
346 /* end of strip */
347 if (IS_EQF(strip->blendout, 0.0f) == 0) {
348 immVertex2f(pos, strip->end - strip->blendout, ymaxc);
349 immVertex2f(pos, strip->end, yminc);
350 }
351 else {
352 immVertex2f(pos, strip->end, ymaxc);
353 }
354
355 immEnd();
356 }
357 }
358
359 /* turn off AA'd lines */
360 GPU_line_smooth(false);
362}
363
364/* helper call to setup dashed-lines for strip outlines */
365static uint nla_draw_use_dashed_outlines(const float color[4], bool muted)
366{
367 /* Note that we use dashed shader here, and make it draw solid lines if not muted... */
368 uint shdr_pos = GPU_vertformat_attr_add(
371
372 float viewport_size[4];
373 GPU_viewport_size_get_f(viewport_size);
374 immUniform2f("viewport_size", viewport_size[2] / UI_SCALE_FAC, viewport_size[3] / UI_SCALE_FAC);
375
376 immUniform1i("colors_len", 0); /* Simple dashes. */
378
379 /* line style: dotted for muted */
380 if (muted) {
381 /* dotted - and slightly thicker for readability of the dashes */
382 immUniform1f("dash_width", 5.0f);
383 immUniform1f("udash_factor", 0.4f);
384 GPU_line_width(1.5f);
385 }
386 else {
387 /* solid line */
388 immUniform1f("udash_factor", 2.0f);
389 GPU_line_width(1.0f);
390 }
391
392 return shdr_pos;
393}
394
399static bool is_nlastrip_enabled(AnimData *adt, NlaTrack *nlt, NlaStrip *strip)
400{
402 BLI_assert(adt);
403 if (!adt) {
404 return true;
405 }
406
407 if ((nlt->flag & NLATRACK_DISABLED) == 0) {
408 return true;
409 }
410
412 return adt->actstrip == strip;
413}
414
415/* main call for drawing a single NLA-strip */
416static void nla_draw_strip(SpaceNla *snla,
417 AnimData *adt,
418 NlaTrack *nlt,
419 NlaStrip *strip,
420 View2D *v2d,
421 float yminc,
422 float ymaxc)
423{
424 /* If there is no 'adt', this strip came from nowhere. */
425 BLI_assert(adt);
426 if (!adt) {
427 return;
428 }
429
430 const bool adt_has_solo_track = (adt->flag & ADT_NLA_SOLO_TRACK);
431 const bool is_track_solo = (nlt->flag & NLATRACK_SOLO);
432 const bool is_other_track_soloed = adt_has_solo_track && !is_track_solo;
433
434 const bool muted = ((nlt->flag & NLATRACK_MUTED) || (strip->flag & NLASTRIP_FLAG_MUTED));
435 float color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
436 uint shdr_pos;
437
438 /* get color of strip */
440
443
444 /* draw extrapolation info first (as backdrop)
445 * - but this should only be drawn if track has some contribution
446 */
447 if ((strip->extendmode != NLASTRIP_EXTEND_NOTHING) && !is_other_track_soloed) {
448 /* enable transparency... */
450
451 switch (strip->extendmode) {
452 /* since this does both sides,
453 * only do the 'before' side, and leave the rest to the next case */
455 /* only need to draw here if there's no strip before since
456 * it only applies in such a situation
457 */
458 if (strip->prev == nullptr) {
459 /* set the drawing color to the color of the strip, but with very faint alpha */
461
462 /* draw the rect to the edge of the screen */
463 immRectf(shdr_pos, v2d->cur.xmin, yminc, strip->start, ymaxc);
464 }
466
467 /* this only draws after the strip */
469 /* only need to try and draw if the next strip doesn't occur immediately after */
470 if ((strip->next == nullptr) || (IS_EQF(strip->next->start, strip->end) == 0)) {
471 /* set the drawing color to the color of the strip, but this time less faint */
473
474 /* draw the rect to the next strip or the edge of the screen */
475 float x2 = strip->next ? strip->next->start : v2d->cur.xmax;
476 immRectf(shdr_pos, strip->end, yminc, x2, ymaxc);
477 }
478 break;
479 }
480
482 }
483
484 /* draw 'inside' of strip itself */
485 const bool is_invalid_location = (strip->flag & NLASTRIP_FLAG_INVALID_LOCATION);
486 if (!is_other_track_soloed && is_nlastrip_enabled(adt, nlt, strip) && !is_invalid_location) {
488
489 /* strip is in normal track */
490 UI_draw_roundbox_corner_set(UI_CNR_ALL); /* all corners rounded */
491 rctf rect;
492 rect.xmin = strip->start;
493 rect.xmax = strip->end;
494 rect.ymin = yminc;
495 rect.ymax = ymaxc;
496 UI_draw_roundbox_4fv(&rect, true, 0.0f, color);
497
498 /* restore current vertex format & program (roundbox trashes it) */
501 }
502 else {
503 /* strip is in disabled track - make less visible */
505
507 immRectf(shdr_pos, strip->start, yminc, strip->end, ymaxc);
509 }
510
511 /* draw strip's control 'curves'
512 * - only if user hasn't hidden them...
513 */
514 if ((snla->flag & SNLA_NOSTRIPCURVES) == 0) {
515 nla_draw_strip_curves(strip, yminc, ymaxc, shdr_pos);
516 }
517
519
520 /* draw markings indicating locations of local markers
521 * (useful for lining up different actions) */
522 if ((snla->flag & SNLA_NOLOCALMARKERS) == 0) {
523 nla_strip_draw_markers(strip, yminc, ymaxc);
524 }
525
526 /* draw strip outline
527 * - color used here is to indicate active vs non-active
528 */
529 if (is_invalid_location) {
530 color[0] = 1.0f;
531 color[1] = color[2] = 0.15f;
532 }
533 else if (strip->flag & NLASTRIP_FLAG_ACTIVE) {
534 /* strip should appear 'sunken', so draw a light border around it */
535 color[0] = color[1] = color[2] = 1.0f; /* FIXME: hardcoded temp-hack colors */
536 }
537 else {
538 /* strip should appear to stand out, so draw a dark border around it */
539 color[0] = color[1] = color[2] = 0.0f; /* FIXME: or 1.0f ?? */
540 }
541
542 /* draw outline
543 * - dashed-line shader is loaded after this block
544 */
545 if (muted) {
546 /* muted - draw dotted, squarish outline (for simplicity) */
547 shdr_pos = nla_draw_use_dashed_outlines(color, muted);
548 imm_draw_box_wire_2d(shdr_pos, strip->start, yminc, strip->end, ymaxc);
549 }
550 else {
551 /* non-muted - draw solid, rounded outline */
552 rctf rect;
553 rect.xmin = strip->start;
554 rect.xmax = strip->end;
555 rect.ymin = yminc;
556 rect.ymax = ymaxc;
557 UI_draw_roundbox_4fv(&rect, false, 0.0f, color);
558
559 /* restore current vertex format & program (roundbox trashes it) */
560 shdr_pos = nla_draw_use_dashed_outlines(color, muted);
561 }
562
563 /* if action-clip strip, draw lines delimiting repeats too (in the same color as outline) */
564 if ((strip->type == NLASTRIP_TYPE_CLIP) && strip->repeat > 1.0f) {
565 float repeatLen = (strip->actend - strip->actstart) * strip->scale;
566
567 /* only draw lines for whole-numbered repeats, starting from the first full-repeat
568 * up to the last full repeat (but not if it lies on the end of the strip)
569 */
571 for (int i = 1; i < strip->repeat; i++) {
572 float repeatPos = strip->start + (repeatLen * i);
573
574 /* don't draw if line would end up on or after the end of the strip */
575 if (repeatPos < strip->end) {
576 immVertex2f(shdr_pos, repeatPos, yminc + 4);
577 immVertex2f(shdr_pos, repeatPos, ymaxc - 4);
578 }
579 }
580 immEnd();
581 }
582 /* or if meta-strip, draw lines delimiting extents of sub-strips
583 * (in same color as outline, if more than 1 exists) */
584 else if ((strip->type == NLASTRIP_TYPE_META) && (strip->strips.first != strip->strips.last)) {
585 const float y = (ymaxc - yminc) * 0.5f + yminc;
586
587 /* up to 2 lines per strip */
589
590 /* only draw first-level of child-strips, but don't draw any lines on the endpoints */
591 LISTBASE_FOREACH (NlaStrip *, cs, &strip->strips) {
592 /* draw start-line if not same as end of previous (and only if not the first strip)
593 * - on upper half of strip
594 */
595 if ((cs->prev) && IS_EQF(cs->prev->end, cs->start) == 0) {
596 immVertex2f(shdr_pos, cs->start, y);
597 immVertex2f(shdr_pos, cs->start, ymaxc);
598 }
599
600 /* draw end-line if not the last strip
601 * - on lower half of strip
602 */
603 if (cs->next) {
604 immVertex2f(shdr_pos, cs->end, yminc);
605 immVertex2f(shdr_pos, cs->end, y);
606 }
607 }
608
609 immEnd();
610 }
611
613}
614
617 NlaTrack *nlt,
618 NlaStrip *strip,
619 View2D *v2d,
620 float xminc,
621 float xmaxc,
622 float yminc,
623 float ymaxc)
624{
625 const bool solo = !((adt && (adt->flag & ADT_NLA_SOLO_TRACK)) &&
626 (nlt->flag & NLATRACK_SOLO) == 0);
627
628 char str[256];
629 size_t str_len;
630 uchar col[4];
631
632 /* just print the name and the range */
633 if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
634 str_len = STRNCPY_RLEN(str, DATA_("Temp-Meta"));
635 }
636 else {
637 str_len = STRNCPY_RLEN(str, strip->name);
638 }
639
640 /* set text color - if colors (see above) are light, draw black text, otherwise draw white */
642 col[0] = col[1] = col[2] = 0;
643 }
644 else {
645 col[0] = col[1] = col[2] = 255;
646 }
647 /* Default strip to 100% opacity. */
648 col[3] = 255;
649
650 /* Reduce text opacity if a track is soloed,
651 * and if target track isn't the soloed track. */
652 if (!solo) {
653 col[3] = 128;
654 }
655
656 /* set bounding-box for text
657 * - padding of 2 'units' on either side
658 */
659 /* TODO: make this centered? */
660 rctf rect;
661 rect.xmin = xminc;
662 rect.ymin = yminc;
663 rect.xmax = xmaxc;
664 rect.ymax = ymaxc;
665
666 /* add this string to the cache of texts to draw */
667 UI_view2d_text_cache_add_rectf(v2d, &rect, str, str_len, col);
668}
669
675 NlaTrack * /*nlt*/, NlaStrip *strip, View2D *v2d, float /*yminc*/, float ymaxc)
676{
677 const float ytol = 1.0f; /* small offset to vertical positioning of text, for legibility */
678 const uchar col[4] = {220, 220, 220, 255}; /* light gray */
679 char numstr[32];
680 size_t numstr_len;
681
682 /* Always draw times above the strip, whereas sequencer drew below + above.
683 * However, we should be fine having everything on top, since these tend to be
684 * quite spaced out.
685 * NOTE: 1 decimal point is a compromise between lack of precision (ints only, as per sequencer)
686 * while also preserving some accuracy, since we do use floats. */
687
688 /* start frame */
689 numstr_len = SNPRINTF_RLEN(numstr, "%.1f", strip->start);
690 UI_view2d_text_cache_add(v2d, strip->start - 1.0f, ymaxc + ytol, numstr, numstr_len, col);
691
692 /* end frame */
693 numstr_len = SNPRINTF_RLEN(numstr, "%.1f", strip->end);
694 UI_view2d_text_cache_add(v2d, strip->end, ymaxc + ytol, numstr, numstr_len, col);
695}
696
697/* ---------------------- */
698
705{
706 if (BLI_listbase_is_empty(&nlt->strips)) {
707 ListBase empty = {nullptr, nullptr};
708 return empty;
709 }
710
711 NlaStrip *first = nullptr;
712 NlaStrip *last = nullptr;
713
714 /* Find the first strip that is within the bounds of the view. */
715 LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) {
716 if (BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax)) {
717 first = last = strip;
718 break;
719 }
720 }
721
722 const bool has_strips_within_bounds = first != nullptr;
723
724 if (has_strips_within_bounds) {
725 /* Find the last visible strip. */
726 for (NlaStrip *strip = first->next; strip; strip = strip->next) {
727 if (!BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax)) {
728 break;
729 }
730 last = strip;
731 }
732 /* Check if the first strip is adjacent to a strip outside the view to the left
733 * that has an extendmode region that should be drawn.
734 * If so, adjust the first strip to include drawing that strip as well.
735 */
736 NlaStrip *prev = first->prev;
737 if (prev && prev->extendmode != NLASTRIP_EXTEND_NOTHING) {
738 first = prev;
739 }
740 }
741 else {
742 /* No immediately visible strips.
743 * Figure out where our view is relative to the strips, then determine
744 * if the view is adjacent to a strip that should have its extendmode
745 * rendered.
746 */
747 NlaStrip *first_strip = static_cast<NlaStrip *>(nlt->strips.first);
748 NlaStrip *last_strip = static_cast<NlaStrip *>(nlt->strips.last);
749 if (first_strip && v2d->cur.xmax < first_strip->start &&
750 first_strip->extendmode == NLASTRIP_EXTEND_HOLD)
751 {
752 /* The view is to the left of all strips and the first strip has an
753 * extendmode that should be drawn.
754 */
755 first = last = first_strip;
756 }
757 else if (last_strip && v2d->cur.xmin > last_strip->end &&
758 last_strip->extendmode != NLASTRIP_EXTEND_NOTHING)
759 {
760 /* The view is to the right of all strips and the last strip has an
761 * extendmode that should be drawn.
762 */
763 first = last = last_strip;
764 }
765 else {
766 /* The view is in the middle of two strips. */
767 LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) {
768 /* Find the strip to the left by finding the strip to the right and getting its prev. */
769 if (v2d->cur.xmax < strip->start) {
770 /* If the strip to the left has an extendmode, set that as the only visible strip. */
771 if (strip->prev && strip->prev->extendmode != NLASTRIP_EXTEND_NOTHING) {
772 first = last = strip->prev;
773 }
774 break;
775 }
776 }
777 }
778 }
779
780 ListBase visible_strips = {first, last};
781 return visible_strips;
782}
783
785{
786 View2D *v2d = &region->v2d;
787 const float pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
788 const float text_margin_x = (8 * UI_SCALE_FAC) * pixelx;
789
790 /* build list of tracks to draw */
791 ListBase anim_data = {nullptr, nullptr};
794 size_t items = ANIM_animdata_filter(
795 ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
796
797 /* Update max-extent of tracks here (taking into account scrollers):
798 * - this is done to allow the track list to be scrollable, but must be done here
799 * to avoid regenerating the list again and/or also because tracks list is drawn first
800 * - offset of NLATRACK_HEIGHT*2 is added to the height of the tracks, as first is for
801 * start of list offset, and the second is as a correction for the scrollers.
802 */
803 int height = NLATRACK_TOT_HEIGHT(ac, items);
804 v2d->tot.ymin = -height;
805
806 /* Loop through tracks, and set up drawing depending on their type. */
807 float ymax = NLATRACK_FIRST_TOP(ac);
808
809 for (bAnimListElem *ale = static_cast<bAnimListElem *>(anim_data.first); ale;
810 ale = ale->next, ymax -= NLATRACK_STEP(snla))
811 {
812 float ymin = ymax - NLATRACK_HEIGHT(snla);
813 float ycenter = (ymax + ymin + 2 * NLATRACK_SKIP - 1) / 2.0f;
814
815 /* check if visible */
816 if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) ||
817 IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax))
818 {
819 /* data to draw depends on the type of track */
820 switch (ale->type) {
821 case ANIMTYPE_NLATRACK: {
822 AnimData *adt = ale->adt;
823 NlaTrack *nlt = static_cast<NlaTrack *>(ale->data);
824 ListBase visible_nla_strips = get_visible_nla_strips(nlt, v2d);
825
826 /* Draw each visible strip in the track. */
827 LISTBASE_FOREACH (NlaStrip *, strip, &visible_nla_strips) {
828 const float xminc = strip->start + text_margin_x;
829 const float xmaxc = strip->end - text_margin_x;
830
831 /* draw the visualization of the strip */
832 nla_draw_strip(snla, adt, nlt, strip, v2d, ymin, ymax);
833
834 /* add the text for this strip to the cache */
835 if (xminc < xmaxc) {
836 nla_draw_strip_text(adt, nlt, strip, v2d, xminc, xmaxc, ymin, ymax);
837 }
838
839 /* if transforming strips (only real reason for temp-metas currently),
840 * add to the cache the frame numbers of the strip's extents
841 */
842 if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
843 nla_draw_strip_frames_text(nlt, strip, v2d, ymin, ymax);
844 }
845 }
846 break;
847 }
848 case ANIMTYPE_NLAACTION: {
849 AnimData *adt = ale->adt;
850
851 /* Draw the manually set intended playback frame range highlight. */
852 if (ale->data) {
853 ANIM_draw_action_framerange(adt, static_cast<bAction *>(ale->data), v2d, ymin, ymax);
854 }
855
859
860 /* just draw a semi-shaded rect spanning the width of the viewable area, based on if
861 * there's data and the action's extrapolation mode. Draw a second darker rect within
862 * which we draw keyframe indicator dots if there's data.
863 */
865
866 /* get colors for drawing */
867 float color[4];
868 nla_action_get_color(adt, static_cast<bAction *>(ale->data), color);
870
871 /* draw slightly shifted up for greater separation from standard tracks,
872 * but also slightly shorter for some more contrast when viewing the strips
873 */
874 switch (adt->act_extendmode) {
877 v2d->cur.xmin,
878 ymin + NLATRACK_SKIP,
879 v2d->cur.xmax,
880 ymax + NLATRACK_SKIP - 1);
881 break;
882 }
884 if (ale->data == nullptr) {
885 /* This can happen if the object itself has no action attached anymore (e.g. after
886 * using "push down"). */
887 break;
888 }
889 const animrig::Action &action = static_cast<bAction *>(ale->data)->wrap();
890 float2 frame_range = action.get_frame_range();
891 BKE_nla_clip_length_ensure_nonzero(&frame_range[0], &frame_range[1]);
892
893 immRectf(
894 pos, frame_range[1], ymin + NLATRACK_SKIP, v2d->cur.xmax, ymax - NLATRACK_SKIP);
895 break;
896 }
898 break;
899 }
900
902
903 /* draw keyframes in the action */
905 adt,
906 static_cast<bAction *>(ale->data),
907 ycenter,
908 ymin + NLATRACK_SKIP,
909 ymax + NLATRACK_SKIP - 1);
910
912 break;
913 }
914 case ANIMTYPE_NONE:
917 case ANIMTYPE_SUMMARY:
918 case ANIMTYPE_SCENE:
919 case ANIMTYPE_OBJECT:
920 case ANIMTYPE_GROUP:
921 case ANIMTYPE_FCURVE:
928 case ANIMTYPE_DSMAT:
929 case ANIMTYPE_DSLAM:
930 case ANIMTYPE_DSCAM:
932 case ANIMTYPE_DSCUR:
933 case ANIMTYPE_DSSKEY:
934 case ANIMTYPE_DSWOR:
935 case ANIMTYPE_DSNTREE:
936 case ANIMTYPE_DSPART:
937 case ANIMTYPE_DSMBALL:
938 case ANIMTYPE_DSARM:
939 case ANIMTYPE_DSMESH:
940 case ANIMTYPE_DSTEX:
941 case ANIMTYPE_DSLAT:
943 case ANIMTYPE_DSSPK:
945 case ANIMTYPE_DSMCLIP:
946 case ANIMTYPE_DSHAIR:
951 case ANIMTYPE_GPLAYER:
957 case ANIMTYPE_PALETTE:
959 break;
960 }
961 }
962 }
963
964 /* Free temporary tracks. */
965 ANIM_animdata_freelist(&anim_data);
966}
967
968/* *********************************************** */
969/* Track List */
970
972 bAnimContext *ac,
973 ARegion *region,
974 const ListBase /*bAnimListElem*/ &anim_data)
975{
976
977 SpaceNla *snla = reinterpret_cast<SpaceNla *>(ac->sl);
978 View2D *v2d = &region->v2d;
979
980 /* need to do a view-sync here, so that the keys area doesn't jump around
981 * (it must copy this) */
982 UI_view2d_sync(nullptr, ac->area, v2d, V2D_LOCK_COPY);
983
984 /* draw tracks */
985 { /* first pass: just the standard GL-drawing for backdrop + text */
986 size_t track_index = 0;
987 float ymax = NLATRACK_FIRST_TOP(ac);
988
989 for (bAnimListElem *ale = static_cast<bAnimListElem *>(anim_data.first); ale;
990 ale = ale->next, ymax -= NLATRACK_STEP(snla), track_index++)
991 {
992 float ymin = ymax - NLATRACK_HEIGHT(snla);
993
994 /* check if visible */
995 if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) ||
996 IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax))
997 {
998 /* draw all tracks using standard channel-drawing API */
999 ANIM_channel_draw(ac, ale, ymin, ymax, track_index);
1000 }
1001 }
1002 }
1003 { /* second pass: UI widgets */
1004 uiBlock *block = UI_block_begin(C, region, __func__, blender::ui::EmbossType::Emboss);
1005 size_t track_index = 0;
1006 float ymax = NLATRACK_FIRST_TOP(ac);
1007
1008 /* set blending again, as may not be set in previous step */
1010
1011 /* Loop through tracks, and set up drawing depending on their type. */
1012 for (bAnimListElem *ale = static_cast<bAnimListElem *>(anim_data.first); ale;
1013 ale = ale->next, ymax -= NLATRACK_STEP(snla), track_index++)
1014 {
1015 float ymin = ymax - NLATRACK_HEIGHT(snla);
1016
1017 /* check if visible */
1018 if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) ||
1019 IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax))
1020 {
1021 /* draw all tracks using standard channel-drawing API */
1022 rctf track_rect;
1023 BLI_rctf_init(&track_rect, 0, v2d->cur.xmax, ymin, ymax);
1024 ANIM_channel_draw_widgets(C, ac, ale, block, &track_rect, track_index);
1025 }
1026 }
1027
1028 UI_block_end(C, block);
1029 UI_block_draw(C, block);
1030
1032 }
1033}
1034
1035/* *********************************************** */
FCurve * BKE_fcurve_find(ListBase *list, const char rna_path[], int array_index)
float evaluate_fcurve(const FCurve *fcu, float evaltime)
void BKE_nla_clip_length_ensure_nonzero(const float *actstart, float *r_actend)
@ NLATIME_CONVERT_MAP
Definition BKE_nla.hh:543
bool BKE_nlastrip_within_bounds(NlaStrip *strip, float min, float max)
#define BLI_assert(a)
Definition BLI_assert.h:46
#define ATTR_FALLTHROUGH
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
MINLINE float min_ff(float a, float b)
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:198
void BLI_rctf_init(struct rctf *rect, float xmin, float xmax, float ymin, float ymax)
Definition rct.cc:404
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:202
#define STRNCPY_RLEN(dst, src)
Definition BLI_string.h:598
#define SNPRINTF_RLEN(dst, format,...)
Definition BLI_string.h:600
unsigned char uchar
unsigned int uint
#define CLAMP(a, b, c)
#define IN_RANGE(a, b, c)
#define ELEM(...)
#define IS_EQF(a, b)
#define DATA_(msgid)
@ NLASTRIP_FLAG_ACTIVE
@ NLASTRIP_FLAG_USR_INFLUENCE
@ NLASTRIP_FLAG_INVALID_LOCATION
@ NLASTRIP_FLAG_TEMP_META
@ NLASTRIP_FLAG_MUTED
@ NLASTRIP_FLAG_SELECT
@ NLASTRIP_FLAG_TWEAKUSER
@ ADT_NLA_SOLO_TRACK
@ ADT_NLA_EDIT_ON
@ NLASTRIP_EXTEND_HOLD_FORWARD
@ NLASTRIP_EXTEND_NOTHING
@ NLASTRIP_EXTEND_HOLD
@ NLASTRIP_TYPE_SOUND
@ NLASTRIP_TYPE_META
@ NLASTRIP_TYPE_TRANSITION
@ NLASTRIP_TYPE_CLIP
@ NLATRACK_SOLO
@ NLATRACK_MUTED
@ NLATRACK_DISABLED
@ SNLA_NOSTRIPCURVES
@ SNLA_NOLOCALMARKERS
#define UI_SCALE_FAC
@ ANIMTYPE_DSSPK
@ ANIMTYPE_DSTEX
@ ANIMTYPE_SUMMARY
@ ANIMTYPE_DSNTREE
@ ANIMTYPE_NLACURVE
@ ANIMTYPE_SHAPEKEY
@ ANIMTYPE_DSMBALL
@ ANIMTYPE_DSCAM
@ ANIMTYPE_DSLIGHTPROBE
@ ANIMTYPE_DSPOINTCLOUD
@ ANIMTYPE_FILLDRIVERS
@ ANIMTYPE_NONE
@ ANIMTYPE_DSPART
@ ANIMTYPE_DSLINESTYLE
@ ANIMTYPE_GROUP
@ ANIMTYPE_ACTION_SLOT
@ ANIMTYPE_SPECIALDATA__UNUSED
@ ANIMTYPE_GREASE_PENCIL_DATABLOCK
@ ANIMTYPE_DSCUR
@ ANIMTYPE_SCENE
@ ANIMTYPE_DSARM
@ ANIMTYPE_NLACONTROLS
@ ANIMTYPE_GPLAYER
@ ANIMTYPE_MASKDATABLOCK
@ ANIMTYPE_ANIMDATA
@ ANIMTYPE_MASKLAYER
@ ANIMTYPE_DSGPENCIL
@ ANIMTYPE_DSLAT
@ ANIMTYPE_NLAACTION
@ ANIMTYPE_DSMCLIP
@ ANIMTYPE_DSMAT
@ ANIMTYPE_NUM_TYPES
@ ANIMTYPE_DSCACHEFILE
@ ANIMTYPE_DSVOLUME
@ ANIMTYPE_FCURVE
@ ANIMTYPE_DSLAM
@ ANIMTYPE_PALETTE
@ ANIMTYPE_GREASE_PENCIL_LAYER
@ ANIMTYPE_FILLACT_LAYERED
@ ANIMTYPE_FILLACTD
@ ANIMTYPE_OBJECT
@ ANIMTYPE_DSMESH
@ ANIMTYPE_GREASE_PENCIL_LAYER_GROUP
@ ANIMTYPE_NLATRACK
@ ANIMTYPE_DSWOR
@ ANIMTYPE_DSSKEY
@ ANIMTYPE_DSHAIR
#define NLATRACK_SKIP
#define NLATRACK_FIRST_TOP(ac)
#define NLATRACK_TOT_HEIGHT(ac, item_amount)
#define NLATRACK_STEP(snla)
eAnimCont_Types
eAnimFilter_Flags
@ ANIMFILTER_DATA_VISIBLE
@ ANIMFILTER_LIST_VISIBLE
@ ANIMFILTER_LIST_CHANNELS
@ ANIMFILTER_FCURVESONLY
#define NLATRACK_HEIGHT(snla)
@ KEYFRAME_SHAPE_FRAME
@ KEYFRAME_HANDLE_NONE
@ KEYFRAME_EXTREME_NONE
void immEnd()
void immUnbindProgram()
void immUniform2f(const char *name, float x, float y)
void immUniformColor4f(float r, float g, float b, float a)
void immVertex2f(uint attr_id, float x, float y)
void immUniformThemeColorShade(int color_id, int offset)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
void immUniform1i(const char *name, int x)
void immBeginAtMost(GPUPrimType, uint max_vertex_len)
void immUniform1f(const char *name, float x)
GPUVertFormat * immVertexFormat()
void immUniformColor4fv(const float rgba[4])
void immUniformColor3f(float r, float g, float b)
void immBegin(GPUPrimType, uint vertex_len)
void immUniformColor3fvAlpha(const float rgb[3], float a)
void immUniformColor3fv(const float rgb[3])
void imm_draw_box_wire_2d(uint pos, float x1, float y1, float x2, float y2)
void immRectf(uint pos, float x1, float y1, float x2, float y2)
@ GPU_PRIM_LINES
@ GPU_PRIM_POINTS
@ GPU_PRIM_LINE_STRIP
@ GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR
@ GPU_SHADER_KEYFRAME_SHAPE
@ GPU_SHADER_3D_UNIFORM_COLOR
void GPU_program_point_size(bool enable)
Definition gpu_state.cc:180
@ 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
void GPU_line_width(float width)
Definition gpu_state.cc:166
void GPU_line_smooth(bool enable)
Definition gpu_state.cc:78
void GPU_viewport_size_get_f(float coords[4])
Definition gpu_state.cc:273
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT_TO_FLOAT_UNIT
@ GPU_FETCH_INT
uint GPU_vertformat_attr_add(GPUVertFormat *, blender::StringRef name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
@ GPU_COMP_U32
@ GPU_COMP_U8
#define C
Definition RandGen.cpp:29
void UI_draw_roundbox_4fv(const rctf *rect, bool filled, float rad, const float col[4])
uiBlock * UI_block_begin(const bContext *C, ARegion *region, std::string name, blender::ui::EmbossType emboss)
void UI_draw_roundbox_corner_set(int type)
@ UI_CNR_ALL
void UI_block_draw(const bContext *C, uiBlock *block)
void UI_block_end(const bContext *C, uiBlock *block)
void UI_GetThemeColor3fv(int colorid, float col[3])
@ TH_NLA_TRANSITION_SEL
@ TH_NLA_META
@ TH_NLA_META_SEL
@ TH_ANIM_ACTIVE
@ TH_NLA_TWEAK
@ TH_STRIP
@ TH_ANIM_INACTIVE
@ TH_NLA_TWEAK_DUPLI
@ TH_NLA_SOUND
@ TH_NLA_TRANSITION
@ TH_STRIP_SELECT
@ TH_NLA_SOUND_SEL
void UI_GetThemeColor4fv(int colorid, float 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
char char char char void UI_view2d_text_cache_add(View2D *v2d, float x, float y, const char *str, size_t str_len, const unsigned char col[4])
Definition view2d.cc:2081
void UI_view2d_text_cache_add_rectf(View2D *v2d, const rctf *rect_view, const char *str, size_t str_len, const unsigned char col[4])
Definition view2d.cc:2111
void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListElem *ale, uiBlock *block, const rctf *rect, size_t channel_index)
void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc, size_t channel_index)
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
size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, const eAnimFilter_Flags filter_mode, void *data, const eAnimCont_Types datatype)
float nlastrip_get_frame(NlaStrip *strip, float cframe, short mode)
float2 get_frame_range() const ATTR_WARN_UNUSED_RESULT
#define floorf(x)
#define str(s)
uint pos
uint col
#define abs
#define filter
void draw_keyframe_shape(const float x, const float y, float size, const bool sel, const eBezTriple_KeyframeType key_type, const eKeyframeShapeDrawOpts mode, const float alpha, const KeyframeShaderBindings *sh_bindings, const short handle_type, const short extreme_type)
bool ED_keylist_all_keys_frame_range(const AnimKeylist *keylist, Bounds< float > *r_frame_range)
AnimKeylist * ED_keylist_create()
void ED_keylist_free(AnimKeylist *keylist)
const ListBase * ED_keylist_listbase(const AnimKeylist *keylist)
bool ED_keylist_is_empty(const AnimKeylist *keylist)
void action_to_keylist(AnimData *adt, bAction *dna_action, AnimKeylist *keylist, const int saction_flag, blender::float2 range)
format
static void nla_draw_strip_text(AnimData *adt, NlaTrack *nlt, NlaStrip *strip, View2D *v2d, float xminc, float xmaxc, float yminc, float ymaxc)
Definition nla_draw.cc:616
static bool is_nlastrip_enabled(AnimData *adt, NlaTrack *nlt, NlaStrip *strip)
Definition nla_draw.cc:399
static void nla_strip_draw_markers(NlaStrip *strip, float yminc, float ymaxc)
Definition nla_draw.cc:214
static void nla_action_draw_keyframes(View2D *v2d, AnimData *adt, bAction *act, float y, float ymin, float ymax)
Definition nla_draw.cc:78
static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc, uint pos)
Definition nla_draw.cc:294
static void nla_strip_get_color_inside(AnimData *adt, NlaStrip *strip, float color[3])
Definition nla_draw.cc:242
static void nla_draw_strip_frames_text(NlaTrack *, NlaStrip *strip, View2D *v2d, float, float ymaxc)
Definition nla_draw.cc:674
static void nla_draw_strip(SpaceNla *snla, AnimData *adt, NlaTrack *nlt, NlaStrip *strip, View2D *v2d, float yminc, float ymaxc)
Definition nla_draw.cc:416
static void nla_actionclip_draw_markers(NlaStrip *strip, float yminc, float ymaxc, int shade, const bool dashed)
Definition nla_draw.cc:169
static uint nla_draw_use_dashed_outlines(const float color[4], bool muted)
Definition nla_draw.cc:365
static ListBase get_visible_nla_strips(NlaTrack *nlt, View2D *v2d)
Definition nla_draw.cc:704
void draw_nla_track_list(const bContext *C, bAnimContext *ac, ARegion *region, const ListBase &anim_data)
Definition nla_draw.cc:971
void nla_action_get_color(AnimData *adt, bAction *act, float color[4])
Definition nla_draw.cc:53
void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region)
Definition nla_draw.cc:784
float wrap(float value, float max, float min)
Definition node_math.h:71
NlaStrip * actstrip
short act_extendmode
void * last
void * first
struct NlaStrip * next
ListBase fcurves
char name[64]
ListBase strips
struct NlaStrip * prev
short extendmode
bAction * act
ListBase strips
ListBase markers
SpaceLink * sl
eAnimCont_Types datatype
ScrArea * area
bAnimListElem * next
float xmax
float xmin
float ymax
float ymin
i
Definition text_draw.cc:230