Blender V5.0
sequencer_timeline_draw.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 * SPDX-FileCopyrightText: 2024 Blender Authors
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later */
5
9
10#include <cmath>
11#include <cstring>
12
13#include "BLI_listbase.h"
14#include "BLI_math_color.h"
15#include "BLI_math_vector.h"
16#include "BLI_path_utils.hh"
17#include "BLI_string_utf8.h"
18#include "BLI_string_utils.hh"
19#include "BLI_task.hh"
20#include "BLI_threads.h"
21#include "BLI_utildefines.h"
22
23#include "DNA_defaults.h"
24#include "DNA_scene_types.h"
25#include "DNA_screen_types.h"
26#include "DNA_sequence_types.h"
27#include "DNA_sound_types.h"
28#include "DNA_space_types.h"
29#include "DNA_userdef_types.h"
30
31#include "BKE_context.hh"
32#include "BKE_fcurve.hh"
33#include "BKE_global.hh"
34#include "BKE_screen.hh"
35#include "BKE_sound.h"
36
37#include "ED_anim_api.hh"
38#include "ED_markers.hh"
39#include "ED_mask.hh"
40#include "ED_sequencer.hh"
41#include "ED_space_api.hh"
42#include "ED_time_scrub_ui.hh"
43
44#include "GPU_immediate.hh"
45#include "GPU_matrix.hh"
46#include "GPU_state.hh"
47
48#include "RNA_prototypes.hh"
49
50#include "SEQ_channels.hh"
51#include "SEQ_connect.hh"
52#include "SEQ_effects.hh"
53#include "SEQ_prefetch.hh"
54#include "SEQ_relations.hh"
55#include "SEQ_render.hh"
56#include "SEQ_retiming.hh"
57#include "SEQ_select.hh"
58#include "SEQ_sequencer.hh"
60#include "SEQ_time.hh"
61#include "SEQ_transform.hh"
62#include "SEQ_utils.hh"
63
64#include "UI_interface_icons.hh"
65#include "UI_resources.hh"
66#include "UI_view2d.hh"
67
68#include "WM_api.hh"
69#include "WM_types.hh"
70
71#include "BLF_api.hh"
72
73/* Own include. */
74#include "sequencer_intern.hh"
77
78namespace blender::ed::vse {
79
80constexpr int MUTE_ALPHA = 120;
81
82constexpr float ICON_SIZE = 12.0f;
83
88
90{
91 const Editing *ed = seq::editing_get(scene);
92 Vector<Strip *> strips;
93
94 LISTBASE_FOREACH (Strip *, strip, ed->current_strips()) {
96 v2d->cur.xmax)
97 {
98 continue;
99 }
101 seq::time_content_end_frame_get(scene, strip)) < v2d->cur.xmin)
102 {
103 continue;
104 }
105 if (strip->channel + 1.0f < v2d->cur.ymin) {
106 continue;
107 }
108 if (strip->channel > v2d->cur.ymax) {
109 continue;
110 }
111 strips.append(strip);
112 }
113 return strips;
114}
115
117{
119
120 ctx.C = C;
121 ctx.region = CTX_wm_region(C);
123 ctx.sseq = CTX_wm_space_seq(C);
125
126 ctx.ed = ctx.scene ? seq::editing_get(ctx.scene) : nullptr;
127 ctx.channels = ctx.ed ? seq::channels_displayed_get(ctx.ed) : nullptr;
128
131
132 ctx.pixely = BLI_rctf_size_y(&ctx.v2d->cur) / (BLI_rcti_size_y(&ctx.v2d->mask) + 1);
133 ctx.pixelx = BLI_rctf_size_x(&ctx.v2d->cur) / (BLI_rcti_size_x(&ctx.v2d->mask) + 1);
134
136
137 ctx.quads = quads_batch;
138
139 return ctx;
140}
141
142static bool seq_draw_waveforms_poll(const SpaceSeq *sseq, const Strip *strip)
143{
144 const bool strip_is_valid = strip->type == STRIP_TYPE_SOUND_RAM && strip->sound != nullptr;
145 const bool overlays_enabled = (sseq->flag & SEQ_SHOW_OVERLAY) != 0;
146 const bool ovelay_option = ((sseq->timeline_overlay.flag & SEQ_TIMELINE_ALL_WAVEFORMS) != 0 ||
147 (strip->flag & SEQ_AUDIO_DRAW_WAVEFORM));
148
150 return false;
151 }
152
153 if (strip_is_valid && overlays_enabled && ovelay_option) {
154 return true;
155 }
156
157 return false;
158}
159
161 const StripDrawContext *strip_ctx)
162{
163 return seq_draw_waveforms_poll(ctx->sseq, strip_ctx->strip) ||
164 strip_ctx->strip->type == STRIP_TYPE_COLOR;
165}
166
168 StripDrawContext *strip_ctx)
169{
170 float threshold = 8 * UI_SCALE_FAC;
171 if (strip_hides_text_overlay_first(ctx, strip_ctx)) {
172 threshold = 20 * UI_SCALE_FAC;
173 }
174
175 const bool overlays_enabled = (ctx->sseq->timeline_overlay.flag &
178
179 strip_ctx->can_draw_text_overlay = (strip_ctx->top - strip_ctx->bottom) / ctx->pixely >=
180 threshold;
181 strip_ctx->can_draw_text_overlay &= overlays_enabled;
182}
183
185 StripDrawContext *strip_ctx)
186{
187 float threshold = 20 * UI_SCALE_FAC;
188 if (strip_hides_text_overlay_first(ctx, strip_ctx)) {
189 threshold = 8 * UI_SCALE_FAC;
190 }
191
192 strip_ctx->can_draw_strip_content = ((strip_ctx->top - strip_ctx->bottom) / ctx->pixely) >
193 threshold;
194}
195
197 StripDrawContext *strip_ctx)
198{
199 float2 threshold{15 * UI_SCALE_FAC, 25 * UI_SCALE_FAC};
200 strip_ctx->can_draw_retiming_overlay = (strip_ctx->top - strip_ctx->bottom) / ctx->pixely >=
201 threshold.y;
202 strip_ctx->can_draw_retiming_overlay &= strip_ctx->strip_length / ctx->pixelx >= threshold.x;
204}
205
207{
208 return min_ff(0.40f, 20 * UI_SCALE_FAC * ctx->pixely);
209}
210
212{
213 using namespace seq;
214 StripDrawContext strip_ctx;
215 Scene *scene = ctx->scene;
216
217 strip_ctx.strip = strip;
218 strip_ctx.bottom = strip->channel + STRIP_OFSBOTTOM;
219 strip_ctx.top = strip->channel + STRIP_OFSTOP;
220 strip_ctx.left_handle = seq::time_left_handle_frame_get(scene, strip);
221 strip_ctx.right_handle = seq::time_right_handle_frame_get(scene, strip);
222 strip_ctx.content_start = seq::time_start_frame_get(strip);
223 strip_ctx.content_end = seq::time_content_end_frame_get(scene, strip);
224
225 if (strip->type == STRIP_TYPE_SOUND_RAM && strip->sound != nullptr) {
226 /* Visualize sub-frame sound offsets. */
227 const double sound_offset = (strip->sound->offset_time + strip->sound_offset) *
228 scene->frames_per_second();
229 strip_ctx.content_start += sound_offset;
230 strip_ctx.content_end += sound_offset;
231 }
232
233 /* Limit body to strip bounds. */
234 strip_ctx.content_start = min_ff(strip_ctx.content_start, strip_ctx.right_handle);
235 strip_ctx.content_end = max_ff(strip_ctx.content_end, strip_ctx.left_handle);
236
237 strip_ctx.strip_length = strip_ctx.right_handle - strip_ctx.left_handle;
238
242 strip_ctx.strip_is_too_small = (!strip_ctx.can_draw_text_overlay &&
243 !strip_ctx.can_draw_strip_content);
244 strip_ctx.is_active_strip = strip == seq::select_active_get(scene);
246 strip_ctx.handle_width = strip_handle_draw_size_get(ctx->scene, strip, ctx->pixelx);
249
250 /* Determine if strip (or contents of meta strip) has missing data/media. */
251 strip_ctx.missing_data_block = !strip_has_valid_data(strip);
252 strip_ctx.missing_media = media_presence_is_missing(scene, strip);
253 strip_ctx.is_connected = seq::is_strip_connected(strip);
254 if (strip->type == STRIP_TYPE_META) {
255 const ListBase *seqbase = &strip->seqbase;
256 LISTBASE_FOREACH (const Strip *, sub, seqbase) {
257 if (!strip_has_valid_data(sub)) {
258 strip_ctx.missing_data_block = true;
259 }
260 if (media_presence_is_missing(scene, sub)) {
261 strip_ctx.missing_media = true;
262 }
263 }
264 }
265
266 if (strip_ctx.can_draw_text_overlay) {
267 strip_ctx.strip_content_top = strip_ctx.top - strip_header_size_get(ctx);
268 }
269 else {
270 strip_ctx.strip_content_top = strip_ctx.top;
271 }
272
273 strip_ctx.is_muted = seq::render_is_muted(ctx->channels, strip);
274 strip_ctx.curve = nullptr;
275 return strip_ctx;
276}
277
279 StripDrawContext &strip_ctx)
280{
281 strip_ctx.curve = nullptr;
282 const bool showing_curve_overlay = strip_ctx.can_draw_strip_content &&
283 (ctx->sseq->flag & SEQ_SHOW_OVERLAY) != 0 &&
284 (ctx->sseq->timeline_overlay.flag &
286 const bool showing_waveform = (strip_ctx.strip->type == STRIP_TYPE_SOUND_RAM) &&
287 !strip_ctx.strip_is_too_small &&
288 seq_draw_waveforms_poll(ctx->sseq, strip_ctx.strip);
289 if (showing_curve_overlay || showing_waveform) {
290 const char *prop_name = strip_ctx.strip->type == STRIP_TYPE_SOUND_RAM ? "volume" :
291 "blend_alpha";
292 strip_ctx.curve = id_data_find_fcurve(
293 &ctx->scene->id, strip_ctx.strip, &RNA_Strip, prop_name, 0, nullptr);
294 if (strip_ctx.curve && BKE_fcurve_is_empty(strip_ctx.curve)) {
295 strip_ctx.curve = nullptr;
296 }
297 }
298}
299
300static void color3ubv_from_seq(const Scene *curscene,
301 const Strip *strip,
302 const bool show_strip_color_tag,
303 const bool is_muted,
304 uchar r_col[3])
305{
306 if (show_strip_color_tag && uint(strip->color_tag) < STRIP_COLOR_TOT &&
307 strip->color_tag != STRIP_COLOR_NONE)
308 {
309 bTheme *btheme = UI_GetTheme();
310 const ThemeStripColor *strip_color = &btheme->strip_color[strip->color_tag];
311 copy_v3_v3_uchar(r_col, strip_color->color);
312 return;
313 }
314
315 uchar blendcol[3];
316
317 /* Sometimes the active theme is not the sequencer theme, e.g. when an operator invokes the file
318 * browser. This makes sure we get the right color values for the theme. */
319 bThemeState theme_state;
320 UI_Theme_Store(&theme_state);
322
323 switch (strip->type) {
324 case STRIP_TYPE_IMAGE:
326 break;
327
328 case STRIP_TYPE_META:
330 break;
331
332 case STRIP_TYPE_MOVIE:
334 break;
335
338 break;
339
340 case STRIP_TYPE_MASK:
342 break;
343
344 case STRIP_TYPE_SCENE:
346
347 if (strip->scene == curscene) {
348 UI_GetColorPtrShade3ubv(r_col, 20, r_col);
349 }
350 break;
351
352 /* Transitions use input colors, fallback for when the input is a transition itself. */
353 case STRIP_TYPE_CROSS:
355 case STRIP_TYPE_WIPE:
357
358 /* Slightly offset hue to distinguish different transition types. */
359 if (strip->type == STRIP_TYPE_GAMCROSS) {
361 }
362 else if (strip->type == STRIP_TYPE_WIPE) {
364 }
365 break;
366
367 /* Effects. */
368 case STRIP_TYPE_SPEED:
369 case STRIP_TYPE_ADD:
370 case STRIP_TYPE_SUB:
371 case STRIP_TYPE_MUL:
374 case STRIP_TYPE_GLOW:
380
381 /* Slightly offset hue to distinguish different effects. */
382 if (strip->type == STRIP_TYPE_ADD) {
384 }
385 else if (strip->type == STRIP_TYPE_SUB) {
387 }
388 else if (strip->type == STRIP_TYPE_MUL) {
390 }
391 else if (strip->type == STRIP_TYPE_ALPHAOVER) {
393 }
394 else if (strip->type == STRIP_TYPE_ALPHAUNDER) {
396 }
397 else if (strip->type == STRIP_TYPE_COLORMIX) {
399 }
400 else if (strip->type == STRIP_TYPE_GAUSSIAN_BLUR) {
402 }
403 else if (strip->type == STRIP_TYPE_GLOW) {
405 }
406 else if (strip->type == STRIP_TYPE_ADJUSTMENT) {
408 }
409 else if (strip->type == STRIP_TYPE_SPEED) {
411 }
412 else if (strip->type == STRIP_TYPE_MULTICAM) {
414 }
415 break;
416
417 case STRIP_TYPE_COLOR:
419 break;
420
423 blendcol[0] = blendcol[1] = blendcol[2] = 128;
424 if (is_muted) {
425 UI_GetColorPtrBlendShade3ubv(r_col, blendcol, 0.5, 20, r_col);
426 }
427 break;
428
429 case STRIP_TYPE_TEXT:
431 break;
432
433 default:
434 r_col[0] = 10;
435 r_col[1] = 255;
436 r_col[2] = 40;
437 break;
438 }
439
440 UI_Theme_Restore(&theme_state);
441}
442
443static void waveform_job_start_if_needed(const bContext *C, const Strip *strip)
444{
445 bSound *sound = strip->sound;
446
447 BLI_spin_lock(static_cast<SpinLock *>(sound->spinlock));
448 if (!sound->waveform) {
449 /* Load the waveform data if it hasn't been loaded and cached already. */
450 if (!(sound->tags & SOUND_TAGS_WAVEFORM_LOADING)) {
451 /* Prevent sounds from reloading. */
453 BLI_spin_unlock(static_cast<SpinLock *>(sound->spinlock));
455 }
456 else {
457 BLI_spin_unlock(static_cast<SpinLock *>(sound->spinlock));
458 }
459 }
460 BLI_spin_unlock(static_cast<SpinLock *>(sound->spinlock));
461}
462
463static float align_frame_with_pixel(float frame_coord, float frames_per_pixel)
464{
465 return round_fl_to_int(frame_coord / frames_per_pixel) * frames_per_pixel;
466}
467
469 const StripDrawContext *strip_ctx)
470{
471 if (!seq_draw_waveforms_poll(timeline_ctx->sseq, strip_ctx->strip) ||
472 strip_ctx->strip_is_too_small)
473 {
474 return;
475 }
476
477 const View2D *v2d = timeline_ctx->v2d;
478 Scene *scene = timeline_ctx->scene;
479 Strip *strip = strip_ctx->strip;
480
481 const bool half_style = (timeline_ctx->sseq->timeline_overlay.flag &
483
484 const float frames_per_pixel = BLI_rctf_size_x(&v2d->cur) / timeline_ctx->region->winx;
485 const float samples_per_frame = SOUND_WAVE_SAMPLES_PER_SECOND / scene->frames_per_second();
486 const float samples_per_pixel = samples_per_frame * frames_per_pixel;
487 const float bottom = strip_ctx->bottom + timeline_ctx->pixely * 2.0f;
488 const float top = strip_ctx->strip_content_top;
489 /* The y coordinate of signal level zero. */
490 const float y_zero = half_style ? bottom : (bottom + top) / 2.0f;
491 /* The y range of unit signal level. */
492 const float y_scale = half_style ? top - bottom : (top - bottom) / 2.0f;
493
494 /* Align strip start with nearest pixel to prevent waveform flickering. */
495 const float strip_start_aligned = align_frame_with_pixel(
496 strip_ctx->left_handle + timeline_ctx->pixelx * 3.0f, frames_per_pixel);
497 /* Offset x1 and x2 values, to match view min/max, if strip is out of bounds. */
498 const float draw_start_frame = max_ff(v2d->cur.xmin, strip_start_aligned);
499 const float draw_end_frame = min_ff(v2d->cur.xmax,
500 strip_ctx->right_handle - timeline_ctx->pixelx * 3.0f);
501 /* Offset must be also aligned, otherwise waveform flickers when moving left handle. */
502 float sample_start_frame = draw_start_frame - (strip->sound->offset_time + strip->sound_offset) *
503 scene->frames_per_second();
504
505 const int pixels_to_draw = round_fl_to_int((draw_end_frame - draw_start_frame) /
506 frames_per_pixel);
507
508 if (pixels_to_draw < 2) {
509 return; /* Not much to draw, exit before running job. */
510 }
511
512 waveform_job_start_if_needed(timeline_ctx->C, strip);
513
514 SoundWaveform *waveform = static_cast<SoundWaveform *>(strip->sound->waveform);
515 if (waveform == nullptr || waveform->length == 0) {
516 return; /* Waveform was not built. */
517 }
518
519 /* Draw zero line (when actual samples close to zero are drawn, they might not cover a pixel. */
520 uchar color[4] = {255, 255, 255, 127};
521 uchar color_clip[4] = {255, 0, 0, 127};
522 uchar color_rms[4] = {255, 255, 255, 204};
523 timeline_ctx->quads->add_line(draw_start_frame, y_zero, draw_end_frame, y_zero, color);
524
525 float prev_y_mid = y_zero;
526 for (int i = 0; i < pixels_to_draw; i++) {
527 float timeline_frame = sample_start_frame + i * frames_per_pixel;
528 float frame_index = seq::give_frame_index(scene, strip, timeline_frame) + strip->anim_startofs;
529 float sample = frame_index * samples_per_frame;
530 int sample_index = round_fl_to_int(sample);
531
532 if (sample_index < 0) {
533 continue;
534 }
535
536 if (sample_index >= waveform->length) {
537 break;
538 }
539
540 float value_min = waveform->data[sample_index * 3];
541 float value_max = waveform->data[sample_index * 3 + 1];
542 float rms = waveform->data[sample_index * 3 + 2];
543
544 if (samples_per_pixel > 1.0f) {
545 /* We need to sum up the values we skip over until the next step. */
546 float next_pos = sample + samples_per_pixel;
547 int end_idx = round_fl_to_int(next_pos);
548
549 for (int j = sample_index + 1; (j < waveform->length) && (j < end_idx); j++) {
550 value_min = min_ff(value_min, waveform->data[j * 3]);
551 value_max = max_ff(value_max, waveform->data[j * 3 + 1]);
552 rms = max_ff(rms, waveform->data[j * 3 + 2]);
553 }
554 }
555
556 float volume = strip->volume;
557 if (strip_ctx->curve != nullptr) {
558 float evaltime = draw_start_frame + (i * frames_per_pixel);
559 volume = evaluate_fcurve(strip_ctx->curve, evaltime);
560 CLAMP_MIN(volume, 0.0f);
561 }
562
563 value_min *= volume;
564 value_max *= volume;
565 rms *= volume;
566
567 bool is_clipping = false;
568 float clamped_min = clamp_f(value_min, -1.0f, 1.0f);
569 float clamped_max = clamp_f(value_max, -1.0f, 1.0f);
570 if (clamped_min != value_min || clamped_max != value_max) {
571 is_clipping = true;
572 }
573 value_min = clamped_min;
574 value_max = clamped_max;
575
576 /* We are drawing only half to the waveform, mirroring the lower part upwards.
577 * If both min and max are on the same side of zero line, we want to draw a bar
578 * between them. If min and max cross zero, we want to fill bar from zero to max
579 * of those. */
580 if (half_style) {
581 bool pos_min = value_min > 0.0f;
582 bool pos_max = value_max > 0.0f;
583 float abs_min = std::abs(value_min);
584 float abs_max = std::abs(value_max);
585 if (pos_min == pos_max) {
586 value_min = std::min(abs_min, abs_max);
587 value_max = std::max(abs_min, abs_max);
588 }
589 else {
590 value_min = 0;
591 value_max = std::max(abs_min, abs_max);
592 }
593 }
594
595 float x1 = draw_start_frame + i * frames_per_pixel;
596 float x2 = draw_start_frame + (i + 1) * frames_per_pixel;
597 float y_min = y_zero + value_min * y_scale;
598 float y_max = y_zero + value_max * y_scale;
599 float y_mid = (y_max + y_min) * 0.5f;
600
601 /* If a bar would be below 2px, make it a line. */
602 if (y_max - y_min < timeline_ctx->pixely * 2) {
603 /* If previous segment was also a line of different enough
604 * height, join them. */
605 if (std::abs(y_mid - prev_y_mid) > timeline_ctx->pixely) {
606 float x0 = draw_start_frame + (i - 1) * frames_per_pixel;
607 timeline_ctx->quads->add_line(x0, prev_y_mid, x1, y_mid, is_clipping ? color_clip : color);
608 }
609 timeline_ctx->quads->add_line(x1, y_mid, x2, y_mid, is_clipping ? color_clip : color);
610 }
611 else {
612 float rms_min = y_zero + max_ff(-rms, value_min) * y_scale;
613 float rms_max = y_zero + min_ff(rms, value_max) * y_scale;
614 /* RMS */
615 timeline_ctx->quads->add_quad(
616 x1, rms_min, x2, rms_max, is_clipping ? color_clip : color_rms);
617 /* Sample */
618 timeline_ctx->quads->add_quad(x1, y_min, x2, y_max, is_clipping ? color_clip : color);
619 }
620
621 prev_y_mid = y_mid;
622 }
623}
624
625static void drawmeta_contents(TimelineDrawContext *timeline_ctx,
626 const StripDrawContext *strip_ctx,
627 float corner_radius)
628{
629 using namespace seq;
630 Strip *strip_meta = strip_ctx->strip;
631 if (!strip_ctx->can_draw_strip_content || (timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) == 0) {
632 return;
633 }
634 if ((strip_meta->type != STRIP_TYPE_META) &&
635 ((strip_meta->type != STRIP_TYPE_SCENE) || (strip_meta->flag & SEQ_SCENE_STRIPS) == 0))
636 {
637 return;
638 }
639
640 Scene *scene = timeline_ctx->scene;
641
642 uchar col[4];
643
644 int chan_min = seq::MAX_CHANNELS;
645 int chan_max = 0;
646 int chan_range = 0;
647 /* Some vertical margin to account for rounded corners, so that contents do
648 * not draw outside them. Can be removed when meta contents are drawn with
649 * full rounded corners masking shader. */
650 const float bottom = strip_ctx->bottom + corner_radius * 0.8f * timeline_ctx->pixely;
651 const float top = strip_ctx->strip_content_top - corner_radius * 0.8f * timeline_ctx->pixely;
652 const float draw_range = top - bottom;
653 if (draw_range < timeline_ctx->pixely) {
654 return;
655 }
656 float draw_height;
657
658 ListBase *meta_seqbase;
659 ListBase *meta_channels;
660 int offset;
661
662 meta_seqbase = seq::get_seqbase_from_strip(strip_meta, &meta_channels, &offset);
663
664 if (!meta_seqbase || BLI_listbase_is_empty(meta_seqbase)) {
665 return;
666 }
667
668 if (strip_meta->type == STRIP_TYPE_SCENE) {
669 offset = strip_meta->start - offset;
670 }
671 else {
672 offset = 0;
673 }
674
675 LISTBASE_FOREACH (Strip *, strip, meta_seqbase) {
676 chan_min = min_ii(chan_min, strip->channel);
677 chan_max = max_ii(chan_max, strip->channel);
678 }
679
680 chan_range = (chan_max - chan_min) + 1;
681 draw_height = draw_range / chan_range;
682
683 col[3] = 196; /* Alpha, used for all meta children. */
684
685 const float meta_x1 = strip_ctx->left_handle;
686 const float meta_x2 = strip_ctx->right_handle;
687
688 /* Draw only immediate children (1 level depth). */
689 LISTBASE_FOREACH (Strip *, strip, meta_seqbase) {
690 float x1_chan = seq::time_left_handle_frame_get(scene, strip) + offset;
691 float x2_chan = seq::time_right_handle_frame_get(scene, strip) + offset;
692 if (x1_chan <= meta_x2 && x2_chan >= meta_x1) {
693 float y_chan = (strip->channel - chan_min) / float(chan_range) * draw_range;
694 float y1_chan, y2_chan;
695
696 if (strip->type == STRIP_TYPE_COLOR) {
697 SolidColorVars *colvars = (SolidColorVars *)strip->effectdata;
698 rgb_float_to_uchar(col, colvars->col);
699 }
700 else {
702 scene, strip, strip_ctx->show_strip_color_tag, strip_ctx->is_muted, col);
703 }
704
705 if (strip_ctx->is_muted || render_is_muted(meta_channels, strip)) {
706 col[3] = 64;
707 }
708 else {
709 col[3] = 196;
710 }
711
712 const bool missing_data = !strip_has_valid_data(strip);
713 const bool missing_media = media_presence_is_missing(scene, strip);
714 if (missing_data || missing_media) {
715 col[0] = 112;
716 col[1] = 0;
717 col[2] = 0;
718 }
719
720 /* Clamp within parent sequence strip bounds. */
721 x1_chan = max_ff(x1_chan, meta_x1);
722 x2_chan = min_ff(x2_chan, meta_x2);
723
724 y1_chan = bottom + y_chan + (draw_height * STRIP_OFSBOTTOM);
725 y2_chan = bottom + y_chan + (draw_height * STRIP_OFSTOP);
726
727 timeline_ctx->quads->add_quad(x1_chan, y1_chan, x2_chan, y2_chan, col);
728 }
729 }
730}
731
732static void draw_handle_transform_text(const TimelineDrawContext *timeline_ctx,
733 const StripDrawContext *strip_ctx,
734 eStripHandle handle)
735{
736 /* Draw numbers for start and end of the strip next to its handles. */
737 if (strip_ctx->strip_is_too_small || (strip_ctx->strip->flag & SELECT) == 0) {
738 return;
739 }
740
741 if (handle_is_selected(strip_ctx->strip, handle) == 0 && (G.moving & G_TRANSFORM_SEQ) == 0) {
742 return;
743 }
744
745 char numstr[64];
747
748 /* Calculate if strip is wide enough for showing the labels. */
749 size_t numstr_len = SNPRINTF_UTF8_RLEN(
750 numstr, "%d%d", int(strip_ctx->left_handle), int(strip_ctx->right_handle));
751 const float tot_width = BLF_width(BLF_default(), numstr, numstr_len);
752
753 if (strip_ctx->strip_length / timeline_ctx->pixelx < 20 + tot_width) {
754 return;
755 }
756
757 const uchar col[4] = {255, 255, 255, 255};
758 const float text_margin = 1.2f * strip_ctx->handle_width;
759 const float text_y = strip_ctx->bottom + 0.09f;
760 float text_x = strip_ctx->left_handle;
761
762 if (handle == STRIP_HANDLE_LEFT) {
763 numstr_len = SNPRINTF_UTF8_RLEN(numstr, "%d", int(strip_ctx->left_handle));
764 text_x += text_margin;
765 }
766 else {
767 numstr_len = SNPRINTF_UTF8_RLEN(numstr, "%d", int(strip_ctx->right_handle - 1));
768 text_x = strip_ctx->right_handle -
769 (text_margin + timeline_ctx->pixelx * BLF_width(BLF_default(), numstr, numstr_len));
770 }
771 UI_view2d_text_cache_add(timeline_ctx->v2d, text_x, text_y, numstr, numstr_len, col);
772}
773
774float strip_handle_draw_size_get(const Scene *scene, Strip *strip, const float pixelx)
775{
776 const float handle_size = pixelx * (5.0f * U.pixelsize);
777
778 /* Ensure that the handle is not wider than a quarter of the strip. */
779 return min_ff(handle_size,
780 (float(seq::time_right_handle_frame_get(scene, strip) -
781 seq::time_left_handle_frame_get(scene, strip)) /
782 4.0f));
783}
784
785static const char *draw_seq_text_get_name(const Strip *strip)
786{
787 const char *name = strip->name + 2;
788 if (name[0] == '\0') {
789 name = seq::strip_give_name(strip);
790 }
791 return name;
792}
793
794static void draw_seq_text_get_source(const Strip *strip, char *r_source, size_t source_maxncpy)
795{
796 *r_source = '\0';
797
798 /* Set source for the most common types. */
799 switch (strip->type) {
800 case STRIP_TYPE_IMAGE:
801 case STRIP_TYPE_MOVIE: {
803 r_source, source_maxncpy, strip->data->dirpath, strip->data->stripdata->filename);
804 break;
805 }
807 if (strip->sound != nullptr) {
808 BLI_strncpy_utf8(r_source, strip->sound->filepath, source_maxncpy);
809 }
810 break;
811 }
812 case STRIP_TYPE_MULTICAM: {
813 BLI_snprintf_utf8(r_source, source_maxncpy, "Channel: %d", strip->multicam_source);
814 break;
815 }
816 case STRIP_TYPE_TEXT: {
817 const TextVars *textdata = static_cast<TextVars *>(strip->effectdata);
818 BLI_strncpy_utf8(r_source, textdata->text_ptr, source_maxncpy);
819 break;
820 }
821 case STRIP_TYPE_SCENE: {
822 if (strip->scene != nullptr) {
823 if (strip->scene_camera != nullptr) {
824 BLI_snprintf_utf8(r_source,
825 source_maxncpy,
826 "%s (%s)",
827 strip->scene->id.name + 2,
828 strip->scene_camera->id.name + 2);
829 }
830 else {
831 BLI_strncpy_utf8(r_source, strip->scene->id.name + 2, source_maxncpy);
832 }
833 }
834 break;
835 }
837 if (strip->clip != nullptr) {
838 BLI_strncpy_utf8(r_source, strip->clip->id.name + 2, source_maxncpy);
839 }
840 break;
841 }
842 case STRIP_TYPE_MASK: {
843 if (strip->mask != nullptr) {
844 BLI_strncpy_utf8(r_source, strip->mask->id.name + 2, source_maxncpy);
845 }
846 break;
847 }
848 }
849}
850
852 const StripDrawContext *strip_ctx,
853 char *r_overlay_string,
854 size_t overlay_string_len)
855{
856 const Strip *strip = strip_ctx->strip;
857
858 const char *text_sep = " | ";
859 const char *text_array[5];
860 int i = 0;
861
863 text_array[i++] = draw_seq_text_get_name(strip);
864 }
865
866 char source[FILE_MAX];
868 draw_seq_text_get_source(strip, source, sizeof(source));
869 if (source[0] != '\0') {
870 if (i != 0) {
871 text_array[i++] = text_sep;
872 }
873 text_array[i++] = source;
874 }
875 }
876
877 char strip_duration_text[16];
879 SNPRINTF_UTF8(strip_duration_text, "%d", int(strip_ctx->strip_length));
880 if (i != 0) {
881 text_array[i++] = text_sep;
882 }
883 text_array[i++] = strip_duration_text;
884 }
885
886 BLI_assert(i <= ARRAY_SIZE(text_array));
887
888 return BLI_string_join_array(r_overlay_string, overlay_string_len, text_array, i);
889}
890
891static void get_strip_text_color(const StripDrawContext *strip_ctx, uchar r_col[4])
892{
893 const Strip *strip = strip_ctx->strip;
894 const bool active_or_selected = (strip->flag & SELECT) || strip_ctx->is_active_strip;
895
896 /* Text: white when selected/active, black otherwise. */
897 r_col[0] = r_col[1] = r_col[2] = r_col[3] = 255;
898
899 /* If not active or selected, draw text black. */
900 if (!active_or_selected) {
901 r_col[0] = r_col[1] = r_col[2] = 0;
902
903 /* On muted and missing media/data-block strips: gray color, reduce opacity. */
904 if (strip_ctx->is_muted || strip_ctx->missing_data_block || strip_ctx->missing_media) {
905 r_col[0] = r_col[1] = r_col[2] = 192;
906 r_col[3] *= 0.66f;
907 }
908 }
909}
910
912 const rctf &rect,
913 int icon_id,
914 const uchar color[4])
915{
918
919 const float icon_size = ICON_SIZE * UI_SCALE_FAC;
920 if (BLI_rctf_size_x(&rect) * 1.1f < icon_size * ctx.pixelx ||
921 BLI_rctf_size_y(&rect) * 1.1f < icon_size * ctx.pixely)
922 {
924 return;
925 }
926
927 const float left = ((rect.xmin - ctx.v2d->cur.xmin) / ctx.pixelx);
928 const float right = ((rect.xmax - ctx.v2d->cur.xmin) / ctx.pixelx);
929 const float bottom = ((rect.ymin - ctx.v2d->cur.ymin) / ctx.pixely);
930 const float top = ((rect.ymax - ctx.v2d->cur.ymin) / ctx.pixely);
931 const float x_offset = (right - left - icon_size) * 0.5f;
932 const float y_offset = (top - bottom - icon_size) * 0.5f;
933
934 const float inv_scale_fac = (ICON_DEFAULT_HEIGHT / ICON_SIZE) * UI_INV_SCALE_FAC;
935
936 UI_icon_draw_ex(left + x_offset,
937 bottom + y_offset,
938 icon_id,
939 inv_scale_fac,
940 1.0f,
941 0.0f,
942 color,
943 false,
945
946 /* Restore view matrix. */
948}
949
950static void draw_strip_icons(TimelineDrawContext *timeline_ctx,
951 const Vector<StripDrawContext> &strips)
952{
953 const float icon_size_x = ICON_SIZE * timeline_ctx->pixelx * UI_SCALE_FAC;
954
955 for (const StripDrawContext &strip : strips) {
956 const bool missing_data = strip.missing_data_block;
957 const bool missing_media = strip.missing_media;
958 const bool is_connected = strip.is_connected;
959 if (!missing_data && !missing_media && !is_connected) {
960 continue;
961 }
962
963 /* Draw icon in the title bar area. */
964 if ((timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) != 0 && !strip.strip_is_too_small) {
965 uchar col[4];
966 get_strip_text_color(&strip, col);
967
968 float icon_indent = 2.0f * strip.handle_width - 4 * timeline_ctx->pixelx * UI_SCALE_FAC;
969 rctf rect;
970 rect.ymin = strip.top - strip_header_size_get(timeline_ctx);
971 rect.ymax = strip.top;
972 rect.xmin = max_ff(strip.left_handle, timeline_ctx->v2d->cur.xmin) + icon_indent;
973 if (missing_data) {
974 rect.xmax = min_ff(strip.right_handle - strip.handle_width, rect.xmin + icon_size_x);
975 draw_icon_centered(*timeline_ctx, rect, ICON_LIBRARY_DATA_BROKEN, col);
976 rect.xmin = rect.xmax;
977 }
978 if (missing_media) {
979 rect.xmax = min_ff(strip.right_handle - strip.handle_width, rect.xmin + icon_size_x);
980 draw_icon_centered(*timeline_ctx, rect, ICON_ERROR, col);
981 rect.xmin = rect.xmax;
982 }
983 if (is_connected) {
984 rect.xmax = min_ff(strip.right_handle - strip.handle_width, rect.xmin + icon_size_x);
985 draw_icon_centered(*timeline_ctx, rect, ICON_LINKED, col);
986 }
987 }
988
989 /* Draw icon in center of content. */
990 if (strip.can_draw_strip_content && strip.strip->type != STRIP_TYPE_META) {
991 rctf rect;
992 rect.xmin = strip.left_handle + strip.handle_width;
993 rect.xmax = strip.right_handle - strip.handle_width;
994 rect.ymin = strip.bottom;
995 rect.ymax = strip.strip_content_top;
996 uchar col[4] = {112, 0, 0, 255};
997 if (missing_data) {
998 draw_icon_centered(*timeline_ctx, rect, ICON_LIBRARY_DATA_BROKEN, col);
999 }
1000 if (missing_media) {
1001 draw_icon_centered(*timeline_ctx, rect, ICON_ERROR, col);
1002 }
1003 }
1004 }
1005}
1006
1007/* Draw info text on a sequence strip. */
1009 const StripDrawContext *strip_ctx)
1010{
1011 if ((timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) == 0) {
1012 return;
1013 }
1014 /* Draw text only if there is enough horizontal or vertical space. */
1015 if ((strip_ctx->strip_length <= 32 * timeline_ctx->pixelx * UI_SCALE_FAC) ||
1016 strip_ctx->strip_is_too_small || !strip_ctx->can_draw_text_overlay)
1017 {
1018 return;
1019 }
1020
1021 char overlay_string[FILE_MAX];
1022 size_t overlay_string_len = draw_seq_text_get_overlay_string(
1023 timeline_ctx, strip_ctx, overlay_string, sizeof(overlay_string));
1024
1025 if (overlay_string_len == 0) {
1026 return;
1027 }
1028
1029 uchar col[4];
1030 get_strip_text_color(strip_ctx, col);
1031
1032 float text_margin = 2.0f * strip_ctx->handle_width;
1033 rctf rect;
1034 rect.xmin = strip_ctx->left_handle + text_margin;
1035 rect.xmax = strip_ctx->right_handle - text_margin;
1036 rect.ymax = strip_ctx->top;
1037 /* Depending on the vertical space, draw text on top or in the center of strip. */
1038 rect.ymin = !strip_ctx->can_draw_strip_content ? strip_ctx->bottom :
1039 strip_ctx->strip_content_top;
1040 rect.xmin = max_ff(rect.xmin, timeline_ctx->v2d->cur.xmin + text_margin);
1041 int num_icons = 0;
1042 if (strip_ctx->missing_data_block) {
1043 num_icons++;
1044 }
1045 if (strip_ctx->missing_media) {
1046 num_icons++;
1047 }
1048 if (strip_ctx->is_connected) {
1049 num_icons++;
1050 }
1051 rect.xmin += num_icons * ICON_SIZE * timeline_ctx->pixelx * UI_SCALE_FAC;
1052 rect.xmin = min_ff(rect.xmin, timeline_ctx->v2d->cur.xmax);
1053
1054 CLAMP(rect.xmax, timeline_ctx->v2d->cur.xmin + text_margin, timeline_ctx->v2d->cur.xmax);
1055 if (rect.xmin >= rect.xmax) { /* No space for label left. */
1056 return;
1057 }
1058
1060 timeline_ctx->v2d, &rect, overlay_string, overlay_string_len, col);
1061}
1062
1063static void draw_strip_offsets(TimelineDrawContext *timeline_ctx,
1064 const StripDrawContext *strip_ctx)
1065{
1066 const Strip *strip = strip_ctx->strip;
1067 if ((timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) == 0) {
1068 return;
1069 }
1070 if (strip_ctx->is_single_image || timeline_ctx->pixely <= 0) {
1071 return;
1072 }
1073 if ((timeline_ctx->sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_OFFSETS) == 0 &&
1074 (strip_ctx->strip != special_preview_get()) &&
1075 (strip_ctx->strip->runtime.flag & STRIP_SHOW_OFFSETS) == 0)
1076 {
1077 return;
1078 }
1079
1080 const Scene *scene = timeline_ctx->scene;
1081
1082 uchar col[4], blend_col[4];
1083 color3ubv_from_seq(scene, strip, strip_ctx->show_strip_color_tag, strip_ctx->is_muted, col);
1084 if (strip->flag & SELECT) {
1086 }
1087 col[3] = strip_ctx->is_muted ? MUTE_ALPHA : 200;
1088 UI_GetColorPtrShade3ubv(col, 10, blend_col);
1089 blend_col[3] = 255;
1090
1091 if (strip_ctx->left_handle > strip_ctx->content_start) {
1092 timeline_ctx->quads->add_quad(strip_ctx->left_handle,
1093 strip_ctx->bottom - timeline_ctx->pixely,
1094 strip_ctx->content_start,
1095 strip_ctx->bottom - STRIP_OFSBOTTOM,
1096 col);
1097 timeline_ctx->quads->add_wire_quad(strip_ctx->left_handle,
1098 strip_ctx->bottom - timeline_ctx->pixely,
1099 strip_ctx->content_start,
1100 strip_ctx->bottom - STRIP_OFSBOTTOM,
1101 blend_col);
1102 }
1103 if (strip_ctx->right_handle < strip_ctx->content_end) {
1104 timeline_ctx->quads->add_quad(strip_ctx->right_handle,
1105 strip_ctx->top + timeline_ctx->pixely,
1106 strip_ctx->content_end,
1107 strip_ctx->top + STRIP_OFSBOTTOM,
1108 col);
1109 timeline_ctx->quads->add_wire_quad(strip_ctx->right_handle,
1110 strip_ctx->top + timeline_ctx->pixely,
1111 strip_ctx->content_end,
1112 strip_ctx->top + STRIP_OFSBOTTOM,
1113 blend_col);
1114 }
1115}
1116
1123 const StripDrawContext *strip_ctx)
1124{
1125 if (!strip_ctx->can_draw_strip_content || (timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) == 0 ||
1126 (timeline_ctx->sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_FCURVES) == 0)
1127 {
1128 return;
1129 }
1130 if (strip_ctx->curve == nullptr) {
1131 return;
1132 }
1133
1134 const int eval_step = max_ii(1, floor(timeline_ctx->pixelx));
1135 uchar color[4] = {0, 0, 0, 38};
1136
1137 /* Clamp curve evaluation to the editor's borders. */
1138 int eval_start = max_ff(strip_ctx->left_handle, timeline_ctx->v2d->cur.xmin);
1139 int eval_end = min_ff(strip_ctx->right_handle, timeline_ctx->v2d->cur.xmax + 1);
1140 if (eval_start >= eval_end) {
1141 return;
1142 }
1143
1144 const float y_height = strip_ctx->top - strip_ctx->bottom;
1145 float prev_x = eval_start;
1146 float prev_val = evaluate_fcurve(strip_ctx->curve, eval_start);
1147 CLAMP(prev_val, 0.0f, 1.0f);
1148 bool skip = false;
1149
1150 for (int timeline_frame = eval_start + eval_step; timeline_frame <= eval_end;
1151 timeline_frame += eval_step)
1152 {
1153 float curve_val = evaluate_fcurve(strip_ctx->curve, timeline_frame);
1154 CLAMP(curve_val, 0.0f, 1.0f);
1155
1156 /* Avoid adding adjacent verts that have the same value. */
1157 if (curve_val == prev_val && timeline_frame < eval_end - eval_step) {
1158 skip = true;
1159 continue;
1160 }
1161
1162 /* If some frames were skipped above, we need to close the shape. */
1163 if (skip) {
1164 timeline_ctx->quads->add_quad(prev_x,
1165 (prev_val * y_height) + strip_ctx->bottom,
1166 prev_x,
1167 strip_ctx->top,
1168 timeline_frame - eval_step,
1169 (prev_val * y_height) + strip_ctx->bottom,
1170 timeline_frame - eval_step,
1171 strip_ctx->top,
1172 color);
1173 skip = false;
1174 prev_x = timeline_frame - eval_step;
1175 }
1176
1177 timeline_ctx->quads->add_quad(prev_x,
1178 (prev_val * y_height) + strip_ctx->bottom,
1179 prev_x,
1180 strip_ctx->top,
1181 timeline_frame,
1182 (curve_val * y_height) + strip_ctx->bottom,
1183 timeline_frame,
1184 strip_ctx->top,
1185 color);
1186 prev_x = timeline_frame;
1187 prev_val = curve_val;
1188 }
1189}
1190
1191/* When active strip is a Multi-cam strip, highlight its source channel. */
1193 const StripDrawContext *strip_ctx)
1194{
1195 Strip *act_strip = seq::select_active_get(timeline_ctx->scene);
1196
1197 if (strip_ctx->strip != act_strip || act_strip == nullptr) {
1198 return;
1199 }
1200 if ((act_strip->flag & SELECT) == 0 || act_strip->type != STRIP_TYPE_MULTICAM) {
1201 return;
1202 }
1203
1204 int channel = act_strip->multicam_source;
1205
1206 if (channel == 0) {
1207 return;
1208 }
1209
1210 View2D *v2d = timeline_ctx->v2d;
1211 uchar color[4] = {255, 255, 255, 48};
1212 timeline_ctx->quads->add_quad(v2d->cur.xmin, channel, v2d->cur.xmax, channel + 1, color);
1213}
1214
1215/* Force redraw, when prefetching and using cache view. */
1216static void seq_prefetch_wm_notify(const bContext *C, Scene *scene)
1217{
1218 if (seq::prefetch_need_redraw(C, scene)) {
1220 }
1221}
1222
1224{
1225 View2D *v2d = ctx->v2d;
1228 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
1232
1233 /* Alternating horizontal stripes. */
1234 int i = max_ii(1, int(v2d->cur.ymin) - 1);
1235 while (i < v2d->cur.ymax) {
1236 if (i & 1) {
1237 immRectf(pos, v2d->cur.xmin, i, v2d->cur.xmax, i + 1);
1238 }
1239 i++;
1240 }
1241
1244}
1245
1246/* Get visible strips into two sets: regular strips, and strips
1247 * that are dragged over other strips right now (e.g. dragging
1248 * selection in the timeline). This is to make the dragged strips
1249 * always render "on top" of others. */
1251 Vector<StripDrawContext> &r_bottom_layer,
1252 Vector<StripDrawContext> &r_top_layer)
1253{
1254 r_bottom_layer.clear();
1255 r_top_layer.clear();
1256
1257 Vector<Strip *> strips = sequencer_visible_strips_get(timeline_ctx->C);
1258 r_bottom_layer.reserve(strips.size());
1259
1260 for (Strip *strip : strips) {
1261 StripDrawContext strip_ctx = strip_draw_context_get(timeline_ctx, strip);
1262 if ((strip->runtime.flag & STRIP_OVERLAP) == 0) {
1263 r_bottom_layer.append(strip_ctx);
1264 }
1265 else {
1266 r_top_layer.append(strip_ctx);
1267 }
1268 }
1269
1270 /* Finding which curves (if any) drive a strip is expensive, do these lookups
1271 * in parallel. */
1272 threading::parallel_for(IndexRange(r_bottom_layer.size()), 64, [&](IndexRange range) {
1273 for (int64_t index : range) {
1274 strip_draw_context_curve_get(timeline_ctx, r_bottom_layer[index]);
1275 }
1276 });
1277 threading::parallel_for(IndexRange(r_top_layer.size()), 64, [&](IndexRange range) {
1278 for (int64_t index : range) {
1279 strip_draw_context_curve_get(timeline_ctx, r_top_layer[index]);
1280 }
1281 });
1282}
1283
1285 StripsDrawBatch &strips_batch,
1286 const Vector<StripDrawContext> &strips)
1287{
1289 wmOrtho2_region_pixelspace(timeline_ctx->region);
1290
1292
1293 const bool show_overlay = (timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) != 0;
1294 const Scene *scene = timeline_ctx->scene;
1295 for (const StripDrawContext &strip : strips) {
1296 SeqStripDrawData &data = strips_batch.add_strip(strip.content_start,
1297 strip.content_end,
1298 strip.top,
1299 strip.bottom,
1300 strip.strip_content_top,
1301 strip.left_handle,
1302 strip.right_handle,
1303 strip.handle_width,
1304 strip.is_single_image);
1305
1306 /* Background color. */
1307 uchar col[4];
1309 color3ubv_from_seq(scene, strip.strip, strip.show_strip_color_tag, strip.is_muted, col);
1310 col[3] = strip.is_muted ? MUTE_ALPHA : 255;
1311 /* Muted strips: turn almost gray. */
1312 if (strip.is_muted) {
1313 uchar muted_color[3] = {128, 128, 128};
1314 UI_GetColorPtrBlendShade3ubv(col, muted_color, 0.5f, 0, col);
1315 }
1316 data.col_background = color_pack(col);
1317
1318 /* Color band state. */
1319 if (show_overlay && (strip.strip->type == STRIP_TYPE_COLOR)) {
1321 SolidColorVars *colvars = (SolidColorVars *)strip.strip->effectdata;
1322 rgb_float_to_uchar(col, colvars->col);
1323 data.col_color_band = color_pack(col);
1324 }
1325
1326 /* Transition state. */
1327 if (show_overlay && strip.can_draw_strip_content &&
1329 {
1331
1332 const Strip *input1 = strip.strip->input1;
1333 const Strip *input2 = strip.strip->input2;
1334
1335 /* Left side. */
1336 if (input1->type == STRIP_TYPE_COLOR) {
1337 rgb_float_to_uchar(col, ((const SolidColorVars *)input1->effectdata)->col);
1338 }
1339 else {
1340 color3ubv_from_seq(scene, input1, strip.show_strip_color_tag, strip.is_muted, col);
1341 }
1342 data.col_transition_in = color_pack(col);
1343
1344 /* Right side. */
1345 if (input2->type == STRIP_TYPE_COLOR) {
1346 rgb_float_to_uchar(col, ((const SolidColorVars *)input2->effectdata)->col);
1347 }
1348 else {
1349 color3ubv_from_seq(scene, input2, strip.show_strip_color_tag, strip.is_muted, col);
1350 /* If the transition inputs are of the same type, draw the right side slightly darker. */
1351 if (input1->type == input2->type) {
1353 }
1354 }
1355 data.col_transition_out = color_pack(col);
1356 }
1357 }
1358 strips_batch.flush_batch();
1361}
1362
1365{
1366 if (strip.missing_data_block || strip.missing_media) {
1367 /* Do not tint title area for muted strips; we want to see gray for them. */
1368 if (!strip.is_muted) {
1370 }
1371 /* Do not tint content area for meta strips; we want to display children. */
1372 if (strip.strip->type != STRIP_TYPE_META) {
1374 }
1375 }
1376}
1377
1379 const TimelineDrawContext *timeline_ctx,
1381{
1382 if (seq::transform_is_locked(timeline_ctx->channels, strip.strip)) {
1383 data.flags |= GPU_SEQ_FLAG_LOCKED;
1384 }
1385}
1386
1388 const TimelineDrawContext *timeline_ctx,
1390{
1391 const bool active = strip.is_active_strip;
1392 const bool selected = strip.strip->flag & SELECT;
1393 uchar4 col{0, 0, 0, 255};
1394
1395 if (selected) {
1397 data.flags |= GPU_SEQ_FLAG_SELECTED;
1398 }
1399 if (active) {
1400 if (selected) {
1402 }
1403 else {
1405 }
1406 data.flags |= GPU_SEQ_FLAG_ACTIVE;
1407 }
1408 if (!selected && !active) {
1409 /* Color for unselected strips is a bit darker than the background. */
1411 }
1412
1413 const bool translating = (G.moving & G_TRANSFORM_SEQ);
1414
1415 const eSeqOverlapMode overlap_mode = seq::tool_settings_overlap_mode_get(timeline_ctx->scene);
1416 const bool use_overwrite = overlap_mode == SEQ_OVERLAP_OVERWRITE;
1417 const bool overlaps = (strip.strip->runtime.flag & STRIP_OVERLAP) && translating;
1418
1419 const bool clamped_l = (strip.strip->runtime.flag & STRIP_CLAMPED_LH);
1420 const bool clamped_r = (strip.strip->runtime.flag & STRIP_CLAMPED_RH);
1421
1422 /* Strip outline is:
1423 * - Red when overlapping with other strips or handles are clamped.
1424 * - Slightly lighter while translating strips. */
1425 if ((translating && overlaps && !use_overwrite) || clamped_l || clamped_r) {
1426 col[0] = 255;
1427 col[1] = col[2] = 33;
1428 data.flags |= GPU_SEQ_FLAG_OVERLAP;
1429 }
1430 else if (translating && selected) {
1432 }
1433
1434 data.col_outline = color_pack(col);
1435}
1436
1438 const TimelineDrawContext *timeline_ctx,
1440{
1441 const Strip *act_strip = seq::select_active_get(timeline_ctx->scene);
1442 const Strip *special_preview = special_preview_get();
1443 /* Highlight if strip is an input of an active strip, or if the strip is solo preview. */
1444 if (act_strip != nullptr && (act_strip->flag & SELECT) != 0) {
1445 if (act_strip->input1 == strip.strip || act_strip->input2 == strip.strip) {
1447 }
1448 }
1449 if (special_preview == strip.strip) {
1451 }
1452}
1453
1455 const TimelineDrawContext *timeline_ctx,
1457{
1458 const Scene *scene = timeline_ctx->scene;
1459 const bool selected = strip.strip->flag & SELECT;
1460 /* Handles on left/right side. */
1461 if (!seq::transform_is_locked(timeline_ctx->channels, strip.strip) &&
1462 can_select_handle(scene, strip.strip, timeline_ctx->v2d))
1463 {
1464 const bool selected_l = selected && handle_is_selected(strip.strip, STRIP_HANDLE_LEFT);
1465 const bool selected_r = selected && handle_is_selected(strip.strip, STRIP_HANDLE_RIGHT);
1466 if (selected_l) {
1468 }
1469 if (selected_r) {
1471 }
1472 }
1473}
1474
1476 StripsDrawBatch &strips_batch,
1477 const Vector<StripDrawContext> &strips)
1478{
1480 wmOrtho2_region_pixelspace(timeline_ctx->region);
1482
1483 for (const StripDrawContext &strip : strips) {
1484 SeqStripDrawData &data = strips_batch.add_strip(strip.content_start,
1485 strip.content_end,
1486 strip.top,
1487 strip.bottom,
1488 strip.strip_content_top,
1489 strip.left_handle,
1490 strip.right_handle,
1491 strip.handle_width,
1492 strip.is_single_image);
1493 data.flags |= GPU_SEQ_FLAG_BORDER;
1495 strip_data_lock_flags_set(strip, timeline_ctx, data);
1496 strip_data_handle_flags_set(strip, timeline_ctx, data);
1497 strip_data_outline_params_set(strip, timeline_ctx, data);
1498 strip_data_highlight_flags_set(strip, timeline_ctx, data);
1499 }
1500
1501 strips_batch.flush_batch();
1504}
1505
1507 const Vector<StripDrawContext> &strips)
1508{
1510 wmOrtho2_region_pixelspace(timeline_ctx->region);
1511
1512 for (const StripDrawContext &strip_ctx : strips) {
1513 sequencer_retiming_draw_continuity(timeline_ctx, strip_ctx);
1514 }
1515 timeline_ctx->quads->draw();
1516
1518}
1519
1520static void draw_seq_strips(TimelineDrawContext *timeline_ctx,
1521 StripsDrawBatch &strips_batch,
1522 const Vector<StripDrawContext> &strips)
1523{
1524 if (strips.is_empty()) {
1525 return;
1526 }
1527
1528 UI_view2d_view_ortho(timeline_ctx->v2d);
1529
1530 /* Draw parts of strips below thumbnails. */
1531 draw_strips_background(timeline_ctx, strips_batch, strips);
1532
1534 const float round_radius = calc_strip_round_radius(timeline_ctx->pixely);
1535 for (const StripDrawContext &strip_ctx : strips) {
1536 draw_strip_offsets(timeline_ctx, &strip_ctx);
1537 drawmeta_contents(timeline_ctx, &strip_ctx, round_radius);
1538 }
1539 timeline_ctx->quads->draw();
1540
1541 /* Draw thumbnails. */
1542 draw_strip_thumbnails(timeline_ctx, strips_batch, strips);
1543
1544 /* Draw parts of strips above thumbnails. */
1546 for (const StripDrawContext &strip_ctx : strips) {
1547 draw_seq_fcurve_overlay(timeline_ctx, &strip_ctx);
1548 draw_seq_waveform_overlay(timeline_ctx, &strip_ctx);
1549 draw_multicam_highlight(timeline_ctx, &strip_ctx);
1550 draw_handle_transform_text(timeline_ctx, &strip_ctx, STRIP_HANDLE_LEFT);
1551 draw_handle_transform_text(timeline_ctx, &strip_ctx, STRIP_HANDLE_RIGHT);
1552 draw_seq_text_overlay(timeline_ctx, &strip_ctx);
1553 sequencer_retiming_speed_draw(timeline_ctx, strip_ctx);
1554 }
1555 timeline_ctx->quads->draw();
1556
1557 /* Draw retiming continuity ranges. */
1558 draw_retiming_continuity_ranges(timeline_ctx, strips);
1559 sequencer_retiming_keys_draw(timeline_ctx, strips);
1560
1561 draw_strips_foreground(timeline_ctx, strips_batch, strips);
1562
1563 /* Draw icons. */
1564 draw_strip_icons(timeline_ctx, strips);
1565
1566 /* Draw text labels. */
1567 UI_view2d_text_cache_draw(timeline_ctx->region);
1569}
1570
1571static void draw_seq_strips(TimelineDrawContext *timeline_ctx, StripsDrawBatch &strips_batch)
1572{
1573 if (timeline_ctx->ed == nullptr) {
1574 return;
1575 }
1576
1577 /* Discard thumbnail requests that are far enough from viewing area:
1578 * by +- 30 frames and +-2 channels outside of current view. */
1579 rctf rect = timeline_ctx->v2d->cur;
1580 rect.xmin -= 30;
1581 rect.xmax += 30;
1582 rect.ymin -= 2;
1583 rect.ymax += 2;
1586
1587 Vector<StripDrawContext> bottom_layer, top_layer;
1588 visible_strips_ordered_get(timeline_ctx, bottom_layer, top_layer);
1589 draw_seq_strips(timeline_ctx, strips_batch, bottom_layer);
1590 draw_seq_strips(timeline_ctx, strips_batch, top_layer);
1591}
1592
1594{
1595 const Scene *scene = ctx->scene;
1596 if (!scene) {
1597 return;
1598 }
1599 const View2D *v2d = ctx->v2d;
1600 const Editing *ed = seq::editing_get(scene);
1601 const int frame_sta = scene->r.sfra;
1602 const int frame_end = scene->r.efra + 1;
1603
1605
1607 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
1609
1610 /* Draw overlay outside of frame range. */
1612
1613 if (frame_sta < frame_end) {
1614 immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, float(frame_sta), v2d->cur.ymax);
1615 immRectf(pos, float(frame_end), v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
1616 }
1617 else {
1618 immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
1619 }
1620
1622
1623 /* Draw frame range boundary. */
1625
1626 immVertex2f(pos, frame_sta, v2d->cur.ymin);
1627 immVertex2f(pos, frame_sta, v2d->cur.ymax);
1628
1629 immVertex2f(pos, frame_end, v2d->cur.ymin);
1630 immVertex2f(pos, frame_end, v2d->cur.ymax);
1631
1632 immEnd();
1633
1634 /* While in meta strip, draw a checkerboard overlay outside of frame range. */
1635 if (ed && !BLI_listbase_is_empty(&ed->metastack)) {
1636 const MetaStack *ms = static_cast<const MetaStack *>(ed->metastack.last);
1638
1640
1641 immUniform4f("color1", 0.0f, 0.0f, 0.0f, 0.22f);
1642 immUniform4f("color2", 1.0f, 1.0f, 1.0f, 0.0f);
1643 immUniform1i("size", 8);
1644
1645 immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, ms->disp_range[0], v2d->cur.ymax);
1646 immRectf(pos, ms->disp_range[1], v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
1647
1649
1652
1654
1655 immVertex2f(pos, ms->disp_range[0], v2d->cur.ymin);
1656 immVertex2f(pos, ms->disp_range[0], v2d->cur.ymax);
1657
1658 immVertex2f(pos, ms->disp_range[1], v2d->cur.ymin);
1659 immVertex2f(pos, ms->disp_range[1], v2d->cur.ymax);
1660
1661 immEnd();
1662 }
1663
1665
1667}
1668
1675
1676/* Draw final cache entries on top of the timeline. */
1677static void draw_cache_final_iter_fn(void *userdata, int timeline_frame)
1678{
1679 CacheDrawData *drawdata = static_cast<CacheDrawData *>(userdata);
1680
1681 /* Same as movie clip cache color, see ED_region_cache_draw_cached_segments. */
1682 const uchar4 col{108, 108, 210, 255};
1683
1684 const View2D *v2d = drawdata->v2d;
1685 float stripe_top = v2d->cur.ymax - (UI_TIME_SCRUB_MARGIN_Y / UI_view2d_scale_get_y(v2d));
1686 float stripe_bot = stripe_top - (UI_TIME_CACHE_MARGIN_Y / UI_view2d_scale_get_y(v2d));
1687 drawdata->quads->add_quad(timeline_frame, stripe_bot, timeline_frame + 1, stripe_top, col);
1688}
1689
1690/* Draw source cache entries at bottom of the strips. */
1691static void draw_cache_source_iter_fn(void *userdata, const Strip *strip, int timeline_frame)
1692{
1693 CacheDrawData *drawdata = static_cast<CacheDrawData *>(userdata);
1694
1695 const uchar4 col{255, 25, 5, 100};
1696 float stripe_bot = strip->channel + STRIP_OFSBOTTOM + drawdata->stripe_ofs_y;
1697 float stripe_top = stripe_bot + drawdata->stripe_ht;
1698 drawdata->quads->add_quad(timeline_frame, stripe_bot, timeline_frame + 1, stripe_top, col);
1699}
1700
1701static void draw_cache_stripe(const Scene *scene,
1702 const Strip *strip,
1703 SeqQuadsBatch &quads,
1704 const float stripe_bot,
1705 const float stripe_ht,
1706 const uchar color[4])
1707{
1708 quads.add_quad(seq::time_left_handle_frame_get(scene, strip),
1709 stripe_bot,
1711 stripe_bot + stripe_ht,
1712 color);
1713}
1714
1715static void draw_cache_background(const bContext *C, CacheDrawData *draw_data)
1716{
1717 const Scene *scene = CTX_data_sequencer_scene(C);
1718 const View2D *v2d = UI_view2d_fromcontext(C);
1719 const SpaceSeq *sseq = CTX_wm_space_seq(C);
1720
1721 /* NOTE: Final bg color is the same as the movie clip cache color.
1722 * See ED_region_cache_draw_background.
1723 */
1724 const uchar4 bg_final{78, 78, 145, 255};
1725 const uchar4 bg_raw{255, 25, 5, 25};
1726
1727 float stripe_bot;
1728 bool dev_ui = (U.flag & USER_DEVELOPER_UI);
1729
1731 /* Draw the final cache on top of the timeline */
1732 float stripe_top = v2d->cur.ymax - (UI_TIME_SCRUB_MARGIN_Y / UI_view2d_scale_get_y(v2d));
1733 stripe_bot = stripe_top - (UI_TIME_CACHE_MARGIN_Y / UI_view2d_scale_get_y(v2d));
1734
1735 draw_data->quads->add_quad(scene->r.sfra, stripe_bot, scene->r.efra, stripe_top, bg_final);
1736 }
1737
1738 if (!dev_ui) {
1739 /* Don't show these cache types below unless developer extras is on. */
1740 return;
1741 }
1742
1744 strips.remove_if([&](Strip *strip) { return strip->type == STRIP_TYPE_SOUND_RAM; });
1745
1746 for (const Strip *strip : strips) {
1747 stripe_bot = strip->channel + STRIP_OFSBOTTOM + draw_data->stripe_ofs_y;
1749 draw_cache_stripe(scene, strip, *draw_data->quads, stripe_bot, draw_data->stripe_ht, bg_raw);
1750 }
1751 }
1752}
1753
1754static void draw_cache_view(const bContext *C)
1755{
1757 const View2D *v2d = UI_view2d_fromcontext(C);
1758 const SpaceSeq *sseq = CTX_wm_space_seq(C);
1759
1760 if ((sseq->flag & SEQ_SHOW_OVERLAY) == 0 || (sseq->cache_overlay.flag & SEQ_CACHE_SHOW) == 0) {
1761 return;
1762 }
1763
1764 float stripe_ofs_y = UI_view2d_region_to_view_y(v2d, 1.0f) - v2d->cur.ymin;
1765 float stripe_ht = UI_view2d_region_to_view_y(v2d, 4.0f * UI_SCALE_FAC * U.pixelsize) -
1766 v2d->cur.ymin;
1767
1768 CLAMP_MAX(stripe_ht, 0.2f);
1769 CLAMP_MIN(stripe_ofs_y, stripe_ht / 2);
1770
1771 SeqQuadsBatch quads;
1772 CacheDrawData userdata;
1773 userdata.v2d = v2d;
1774 userdata.stripe_ofs_y = stripe_ofs_y;
1775 userdata.stripe_ht = stripe_ht;
1776 userdata.quads = &quads;
1777
1779
1780 draw_cache_background(C, &userdata);
1783 }
1784 if ((U.flag & USER_DEVELOPER_UI) && (sseq->cache_overlay.flag & SEQ_CACHE_SHOW_RAW)) {
1786 }
1787
1788 quads.draw();
1790}
1791
1792/* Draw sequencer timeline. */
1793static void draw_overlap_frame_indicator(const Scene *scene, const View2D *v2d)
1794{
1795 int overlap_frame = (scene->ed->overlay_frame_flag & SEQ_EDIT_OVERLAY_FRAME_ABS) ?
1796 scene->ed->overlay_frame_abs :
1797 scene->r.cfra + scene->ed->overlay_frame_ofs;
1798
1800 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
1802 float viewport_size[4];
1803 GPU_viewport_size_get_f(viewport_size);
1804 immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
1805 /* Shader may have color set from past usage - reset it. */
1806 immUniform1i("colors_len", 0);
1807 immUniform1f("dash_width", 20.0f * U.pixelsize);
1808 immUniform1f("udash_factor", 0.5f);
1810
1812 immVertex2f(pos, overlap_frame, v2d->cur.ymin);
1813 immVertex2f(pos, overlap_frame, v2d->cur.ymax);
1814 immEnd();
1815
1817}
1818
1820{
1821 if ((ctx->sseq->flag & SEQ_SHOW_OVERLAY) == 0 ||
1823 {
1824 return;
1825 }
1826
1827 const Scene *scene = ctx->scene;
1828 if (scene == nullptr) {
1829 /* If we don't have a scene available, pick what we defined as default for framerate to show
1830 * *something*. */
1832 }
1834 ctx->v2d, scene, (ctx->sseq->flag & SEQ_DRAWFRAMES) == 0, false);
1835}
1836
1838{
1839 if (!ED_markers_region_visible(CTX_wm_area(ctx->C), ctx->region)) {
1840 return;
1841 }
1842 if (ctx->scene == nullptr) {
1843 return;
1844 }
1845
1846 UI_view2d_view_orthoSpecial(ctx->region, ctx->v2d, true);
1848}
1849
1851{
1852 if ((ctx->sseq->gizmo_flag & SEQ_GIZMO_HIDE) != 0) {
1853 return;
1854 }
1855
1856 WM_gizmomap_draw(ctx->region->runtime->gizmo_map, ctx->C, WM_GIZMOMAP_DRAWSTEP_2D);
1857}
1858
1867
1874
1876{
1877 SeqQuadsBatch quads_batch;
1878 TimelineDrawContext ctx = timeline_draw_context_get(C, &quads_batch);
1879 StripsDrawBatch strips_batch(ctx.v2d);
1880
1884 draw_timeline_grid(&ctx);
1886 draw_seq_strips(&ctx, strips_batch);
1889 if (ctx.scene) {
1890 ANIM_draw_previewrange(ctx.scene, ctx.v2d, 1);
1891 }
1894 if (ctx.scene) {
1895 const int fps = round_db_to_int(ctx.scene->frames_per_second());
1896 ED_time_scrub_draw(region, ctx.scene, !(ctx.sseq->flag & SEQ_DRAWFRAMES), true, fps);
1897 }
1898
1899 if (ctx.scene) {
1901 }
1902}
1903
1905{
1906 const Scene *scene = CTX_data_sequencer_scene(C);
1907 if (!scene) {
1908 return;
1909 }
1910 const SpaceSeq *sseq = CTX_wm_space_seq(C);
1911 View2D *v2d = &region->v2d;
1912
1913 if (scene->ed != nullptr) {
1917 draw_overlap_frame_indicator(scene, v2d);
1918 }
1920 }
1921
1923 region, scene, !(sseq->flag & SEQ_DRAWFRAMES), region->winy >= UI_ANIM_MINY);
1924
1925 if (region->winy > UI_ANIM_MINY) {
1926 const Editing *ed = seq::editing_get(scene);
1927 if (ed) {
1928 const ListBase *seqbase = seq::active_seqbase_get(ed);
1929 seq::timeline_boundbox(scene, seqbase, &v2d->tot);
1930 const rcti scroller_mask = ED_time_scrub_clamp_scroller_mask(v2d->mask);
1931 region->v2d.scroll |= V2D_SCROLL_BOTTOM;
1932 UI_view2d_scrollers_draw(v2d, &scroller_mask);
1933 }
1934 }
1935 else {
1936 region->v2d.scroll &= ~V2D_SCROLL_BOTTOM;
1937 }
1938}
1939
1940} // namespace blender::ed::vse
ScrArea * CTX_wm_area(const bContext *C)
SpaceSeq * CTX_wm_space_seq(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
Scene * CTX_data_sequencer_scene(const bContext *C)
bool BKE_fcurve_is_empty(const FCurve *fcu)
float evaluate_fcurve(const FCurve *fcu, float evaltime)
FCurve * id_data_find_fcurve(ID *id, void *data, StructRNA *type, const char *prop_name, int index, bool *r_driven)
@ G_TRANSFORM_SEQ
#define SOUND_WAVE_SAMPLES_PER_SECOND
Definition BKE_sound.h:10
int BLF_set_default()
int BLF_default()
float BLF_width(int fontid, const char *str, size_t str_len, ResultBLF *r_info=nullptr) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2)
Definition blf.cc:802
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
MINLINE int round_fl_to_int(float a)
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE float clamp_f(float value, float min, float max)
MINLINE float min_ff(float a, float b)
MINLINE int max_ii(int a, int b)
MINLINE int round_db_to_int(double a)
MINLINE void rgb_float_to_uchar(unsigned char r_col[3], const float col_f[3])
void rgb_byte_set_hue_float_offset(unsigned char rgb[3], float hue_offset)
MINLINE void copy_v3_v3_uchar(unsigned char r[3], const unsigned char a[3])
#define FILE_MAX
#define BLI_path_join(...)
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:198
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
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition BLI_rect.h:206
size_t size_t size_t BLI_snprintf_utf8(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
#define SNPRINTF_UTF8(dst, format,...)
#define SNPRINTF_UTF8_RLEN(dst, format,...)
char * BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
size_t BLI_string_join_array(char *result, size_t result_maxncpy, const char *strings[], uint strings_num) ATTR_NONNULL()
unsigned char uchar
unsigned int uint
pthread_spinlock_t SpinLock
void BLI_spin_unlock(SpinLock *spin)
Definition threads.cc:430
void BLI_spin_lock(SpinLock *spin)
Definition threads.cc:405
#define CLAMP(a, b, c)
#define CLAMP_MAX(a, c)
#define ARRAY_SIZE(arr)
#define ELEM(...)
#define CLAMP_MIN(a, b)
#define DNA_struct_default_get(struct_name)
eSeqOverlapMode
@ SEQ_OVERLAP_OVERWRITE
@ RGN_TYPE_WINDOW
#define STRIP_OFSBOTTOM
#define STRIP_OFSTOP
@ STRIP_SHOW_OFFSETS
@ STRIP_OVERLAP
@ STRIP_CLAMPED_LH
@ STRIP_CLAMPED_RH
@ STRIP_TYPE_GAUSSIAN_BLUR
@ STRIP_TYPE_GAMCROSS
@ STRIP_TYPE_SCENE
@ STRIP_TYPE_MOVIECLIP
@ STRIP_TYPE_COLORMIX
@ STRIP_TYPE_WIPE
@ STRIP_TYPE_TEXT
@ STRIP_TYPE_SOUND_RAM
@ STRIP_TYPE_ADD
@ STRIP_TYPE_IMAGE
@ STRIP_TYPE_MOVIE
@ STRIP_TYPE_GLOW
@ STRIP_TYPE_SUB
@ STRIP_TYPE_MUL
@ STRIP_TYPE_SPEED
@ STRIP_TYPE_COLOR
@ STRIP_TYPE_ADJUSTMENT
@ STRIP_TYPE_META
@ STRIP_TYPE_MULTICAM
@ STRIP_TYPE_MASK
@ STRIP_TYPE_ALPHAUNDER
@ STRIP_TYPE_CROSS
@ STRIP_TYPE_ALPHAOVER
@ STRIP_COLOR_NONE
@ STRIP_COLOR_TOT
@ SEQ_EDIT_OVERLAY_FRAME_ABS
@ SEQ_EDIT_OVERLAY_FRAME_SHOW
@ SEQ_SCENE_STRIPS
@ SEQ_AUDIO_DRAW_WAVEFORM
@ SOUND_TAGS_WAVEFORM_LOADING
@ SPACE_SEQ
@ SEQ_TIMELINE_SHOW_FCURVES
@ SEQ_TIMELINE_SHOW_STRIP_DURATION
@ SEQ_TIMELINE_SHOW_STRIP_OFFSETS
@ SEQ_TIMELINE_ALL_WAVEFORMS
@ SEQ_TIMELINE_WAVEFORMS_HALF
@ SEQ_TIMELINE_SHOW_STRIP_SOURCE
@ SEQ_TIMELINE_SHOW_STRIP_NAME
@ SEQ_TIMELINE_SHOW_GRID
@ SEQ_TIMELINE_NO_WAVEFORMS
@ SEQ_TIMELINE_SHOW_STRIP_COLOR_TAG
@ SEQ_CACHE_SHOW_RAW
@ SEQ_CACHE_SHOW
@ SEQ_CACHE_SHOW_FINAL_OUT
@ SEQ_DRAWFRAMES
@ SEQ_SHOW_OVERLAY
@ SEQ_GIZMO_HIDE
#define UI_SCALE_FAC
#define UI_INV_SCALE_FAC
@ USER_DEVELOPER_UI
@ V2D_SCROLL_BOTTOM
@ DRAW_MARKERS_MARGIN
Definition ED_markers.hh:28
void ED_region_draw_cb_draw(const bContext *C, ARegion *region, int type)
#define REGION_DRAW_POST_VIEW
#define REGION_DRAW_PRE_VIEW
void GPU_framebuffer_bind_no_srgb(blender::gpu::FrameBuffer *fb)
void GPU_framebuffer_bind(blender::gpu::FrameBuffer *fb)
void immUniform4f(const char *name, float x, float y, float z, float w)
void immEnd()
void immUnbindProgram()
void immBindBuiltinProgram(GPUBuiltinShader shader_id)
void immUniform2f(const char *name, float x, float y)
void immUniformThemeColorShadeAlpha(int color_id, int color_offset, int alpha_offset)
void immVertex2f(uint attr_id, float x, float y)
void immUniformThemeColor(int color_id)
void immUniformThemeColorShade(int color_id, int offset)
void immUniform1i(const char *name, int x)
void immUniform1f(const char *name, float x)
GPUVertFormat * immVertexFormat()
void immBegin(GPUPrimType, uint vertex_len)
void immRectf(uint pos, float x1, float y1, float x2, float y2)
void GPU_matrix_push_projection()
void GPU_matrix_pop_projection()
@ GPU_PRIM_LINES
@ GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR
@ GPU_SHADER_2D_CHECKER
@ GPU_SHADER_3D_UNIFORM_COLOR
@ GPU_SEQ_FLAG_HIGHLIGHT
@ GPU_SEQ_FLAG_BACKGROUND
@ GPU_SEQ_FLAG_LOCKED
@ GPU_SEQ_FLAG_MISSING_CONTENT
@ GPU_SEQ_FLAG_SELECTED
@ GPU_SEQ_FLAG_BORDER
@ GPU_SEQ_FLAG_COLOR_BAND
@ GPU_SEQ_FLAG_TRANSITION
@ GPU_SEQ_FLAG_SELECTED_LH
@ GPU_SEQ_FLAG_SELECTED_RH
@ GPU_SEQ_FLAG_OVERLAP
@ GPU_SEQ_FLAG_ACTIVE
@ GPU_SEQ_FLAG_MISSING_TITLE
@ GPU_DEPTH_NONE
Definition GPU_state.hh:111
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
@ GPU_BLEND_ALPHA_PREMULT
Definition GPU_state.hh:88
void GPU_blend(GPUBlend blend)
Definition gpu_state.cc:42
void GPU_depth_test(GPUDepthTest test)
Definition gpu_state.cc:68
void GPU_viewport_size_get_f(float coords[4])
Definition gpu_state.cc:273
uint GPU_vertformat_attr_add(GPUVertFormat *format, blender::StringRef name, blender::gpu::VertAttrType type)
blender::gpu::FrameBuffer * GPU_viewport_framebuffer_overlay_get(GPUViewport *viewport)
#define C
Definition RandGen.cpp:29
#define ICON_DEFAULT_HEIGHT
#define UI_NO_ICON_OVERLAY_TEXT
void UI_icon_draw_ex(float x, float y, int icon_id, float aspect, float alpha, float desaturate, const uchar mono_color[4], bool mono_border, const IconTextOverlay *text_overlay, const bool inverted=false)
void UI_Theme_Store(bThemeState *theme_state)
void UI_Theme_Restore(const bThemeState *theme_state)
@ TH_ROW_ALTERNATE
@ TH_SEQ_SELECTED
@ TH_BACK
@ TH_SEQ_TRANSITION
@ TH_SEQ_TEXT
@ TH_SEQ_MASK
@ TH_SEQ_MOVIE
@ TH_SEQ_COLOR
@ TH_SEQ_META
@ TH_CFRAME
@ TH_SEQ_AUDIO
@ TH_SEQ_ACTIVE
@ TH_SEQ_EFFECT
@ TH_SEQ_SCENE
@ TH_SEQ_MOVIECLIP
@ TH_SEQ_IMAGE
void UI_GetColorPtrBlendShade3ubv(const unsigned char cp1[3], const unsigned char cp2[3], float fac, int offset, unsigned char r_col[3])
void UI_ThemeClearColor(int colorid)
void UI_GetThemeColor3ubv(int colorid, unsigned char col[3])
bTheme * UI_GetTheme()
void UI_GetThemeColorShade3ubv(int colorid, int offset, unsigned char col[3])
void UI_SetTheme(int spacetype, int regionid)
void UI_GetColorPtrShade3ubv(const unsigned char cp[3], int offset, unsigned char r_col[3])
#define UI_ANIM_MINY
Definition UI_view2d.hh:481
void UI_view2d_view_orthoSpecial(ARegion *region, View2D *v2d, bool xaxis)
Definition view2d.cc:1136
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:2082
void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
Definition view2d.cc:1504
#define UI_TIME_CACHE_MARGIN_Y
Definition UI_view2d.hh:480
void UI_view2d_view_restore(const bContext *C)
Definition view2d.cc:1162
void UI_view2d_text_cache_draw(ARegion *region)
Definition view2d.cc:2142
float UI_view2d_region_to_view_y(const View2D *v2d, float y)
Definition view2d.cc:1662
#define UI_TIME_SCRUB_MARGIN_Y
Definition UI_view2d.hh:479
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:2112
void UI_view2d_view_ortho(const View2D *v2d)
Definition view2d.cc:1095
void UI_view2d_draw_lines_x__discrete_frames_or_seconds(const View2D *v2d, const Scene *scene, bool display_seconds, bool display_minor_lines)
View2D * UI_view2d_fromcontext(const bContext *C)
Definition view2d.cc:1855
float UI_view2d_scale_get_y(const View2D *v2d)
Definition view2d.cc:1925
@ WM_GIZMOMAP_DRAWSTEP_2D
#define ND_SEQUENCER
Definition WM_types.hh:437
#define NC_SCENE
Definition WM_types.hh:378
void ANIM_draw_previewrange(const Scene *scene, View2D *v2d, int end_frame_width)
Definition anim_draw.cc:82
bool ED_markers_region_visible(const ScrArea *area, const ARegion *region)
void ED_markers_draw(const bContext *C, int flag)
#define U
BMesh const char void * data
float evaltime
int64_t size() const
int64_t remove_if(Predicate &&predicate)
void append(const T &value)
bool is_empty() const
void reserve(const int64_t min_capacity)
void add_quad(float x1, float y1, float x2, float y2, const uchar color[4])
void add_line(float x1, float y1, float x2, float y2, const uchar color[4])
void add_wire_quad(float x1, float y1, float x2, float y2, const uchar color[4])
SeqStripDrawData & add_strip(float content_start, float content_end, float top, float bottom, float content_top, float left_handle, float right_handle, float handle_width, bool single_image)
#define SELECT
uint pos
uint col
uint top
#define active
#define floor
static int left
#define G(x, y, z)
static void visible_strips_ordered_get(TimelineDrawContext *timeline_ctx, Vector< StripDrawContext > &r_bottom_layer, Vector< StripDrawContext > &r_top_layer)
static void draw_seq_text_overlay(TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx)
void sequencer_preview_add_sound(const bContext *C, const Strip *strip)
float calc_strip_round_radius(float pixely)
static const char * draw_seq_text_get_name(const Strip *strip)
static void draw_cache_final_iter_fn(void *userdata, int timeline_frame)
static void draw_seq_timeline_channels(TimelineDrawContext *ctx)
void sequencer_retiming_draw_continuity(const TimelineDrawContext *timeline_ctx, const StripDrawContext &strip_ctx)
static void get_strip_text_color(const StripDrawContext *strip_ctx, uchar r_col[4])
static void draw_strip_offsets(TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx)
static float align_frame_with_pixel(float frame_coord, float frames_per_pixel)
static void draw_retiming_continuity_ranges(TimelineDrawContext *timeline_ctx, const Vector< StripDrawContext > &strips)
bool handle_is_selected(const Strip *strip, eStripHandle handle)
void sequencer_retiming_speed_draw(const TimelineDrawContext *timeline_ctx, const StripDrawContext &strip_ctx)
static void draw_seq_strips(TimelineDrawContext *timeline_ctx, StripsDrawBatch &strips_batch, const Vector< StripDrawContext > &strips)
static bool seq_draw_waveforms_poll(const SpaceSeq *sseq, const Strip *strip)
static void strip_data_outline_params_set(const StripDrawContext &strip, const TimelineDrawContext *timeline_ctx, SeqStripDrawData &data)
float strip_handle_draw_size_get(const Scene *scene, Strip *strip, float pixelx)
static void draw_timeline_post_view_callbacks(TimelineDrawContext *ctx)
uint color_pack(const uchar rgba[4])
static void strip_data_highlight_flags_set(const StripDrawContext &strip, const TimelineDrawContext *timeline_ctx, SeqStripDrawData &data)
static void draw_seq_fcurve_overlay(TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx)
void draw_timeline_seq(const bContext *C, ARegion *region)
void draw_strip_thumbnails(TimelineDrawContext *ctx, StripsDrawBatch &strips_batch, const blender::Vector< StripDrawContext > &strips)
static void draw_multicam_highlight(TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx)
void sequencer_retiming_keys_draw(const TimelineDrawContext *timeline_ctx, blender::Span< StripDrawContext > strips)
static void draw_overlap_frame_indicator(const Scene *scene, const View2D *v2d)
static TimelineDrawContext timeline_draw_context_get(const bContext *C, SeqQuadsBatch *quads_batch)
static void draw_icon_centered(TimelineDrawContext &ctx, const rctf &rect, int icon_id, const uchar color[4])
static void draw_cache_view(const bContext *C)
static void drawmeta_contents(TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx, float corner_radius)
bool can_select_handle(const Scene *scene, const Strip *strip, const View2D *v2d)
static void strip_draw_context_set_strip_content_visibility(TimelineDrawContext *ctx, StripDrawContext *strip_ctx)
static void draw_timeline_pre_view_callbacks(TimelineDrawContext *ctx)
static void strip_draw_context_set_text_overlay_visibility(TimelineDrawContext *ctx, StripDrawContext *strip_ctx)
bool retiming_keys_can_be_displayed(const SpaceSeq *sseq)
static void draw_strips_background(TimelineDrawContext *timeline_ctx, StripsDrawBatch &strips_batch, const Vector< StripDrawContext > &strips)
static void seq_prefetch_wm_notify(const bContext *C, Scene *scene)
static void draw_cache_stripe(const Scene *scene, const Strip *strip, SeqQuadsBatch &quads, const float stripe_bot, const float stripe_ht, const uchar color[4])
static void draw_seq_waveform_overlay(TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx)
static void draw_cache_background(const bContext *C, CacheDrawData *draw_data)
static void draw_cache_source_iter_fn(void *userdata, const Strip *strip, int timeline_frame)
static size_t draw_seq_text_get_overlay_string(TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx, char *r_overlay_string, size_t overlay_string_len)
static void draw_handle_transform_text(const TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx, eStripHandle handle)
void draw_timeline_seq_display(const bContext *C, ARegion *region)
static void strip_data_missing_media_flags_set(const StripDrawContext &strip, SeqStripDrawData &data)
static bool strip_hides_text_overlay_first(const TimelineDrawContext *ctx, const StripDrawContext *strip_ctx)
static void draw_timeline_sfra_efra(TimelineDrawContext *ctx)
static float strip_header_size_get(TimelineDrawContext *ctx)
static void waveform_job_start_if_needed(const bContext *C, const Strip *strip)
static void strip_draw_context_curve_get(const TimelineDrawContext *ctx, StripDrawContext &strip_ctx)
static void color3ubv_from_seq(const Scene *curscene, const Strip *strip, const bool show_strip_color_tag, const bool is_muted, uchar r_col[3])
static void draw_timeline_markers(TimelineDrawContext *ctx)
static void draw_timeline_gizmos(TimelineDrawContext *ctx)
static StripDrawContext strip_draw_context_get(TimelineDrawContext *ctx, Strip *strip)
static void strip_data_handle_flags_set(const StripDrawContext &strip, const TimelineDrawContext *timeline_ctx, SeqStripDrawData &data)
static void draw_strip_icons(TimelineDrawContext *timeline_ctx, const Vector< StripDrawContext > &strips)
blender::Vector< Strip * > sequencer_visible_strips_get(const bContext *C)
static void draw_seq_text_get_source(const Strip *strip, char *r_source, size_t source_maxncpy)
static void draw_timeline_grid(TimelineDrawContext *ctx)
static void strip_data_lock_flags_set(const StripDrawContext &strip, const TimelineDrawContext *timeline_ctx, SeqStripDrawData &data)
static void strip_draw_context_set_retiming_overlay_visibility(TimelineDrawContext *ctx, StripDrawContext *strip_ctx)
static void draw_strips_foreground(TimelineDrawContext *timeline_ctx, StripsDrawBatch &strips_batch, const Vector< StripDrawContext > &strips)
bool render_is_muted(const ListBase *channels, const Strip *strip)
Definition render.cc:2110
int time_right_handle_frame_get(const Scene *scene, const Strip *strip)
ListBase * channels_displayed_get(const Editing *ed)
Definition channels.cc:28
bool prefetch_need_redraw(const bContext *C, Scene *scene)
Definition prefetch.cc:644
float time_content_end_frame_get(const Scene *scene, const Strip *strip)
blender::Map< SeqRetimingKey *, Strip * > retiming_selection_get(const Editing *ed)
void timeline_boundbox(const Scene *scene, const ListBase *seqbase, rctf *r_rect)
void source_image_cache_iterate(Scene *scene, void *userdata, void callback_iter(void *userdata, const Strip *strip, int timeline_frame))
void final_image_cache_iterate(Scene *scene, void *userdata, void callback_iter(void *userdata, int timeline_frame))
float give_frame_index(const Scene *scene, const Strip *strip, float timeline_frame)
Definition strip_time.cc:52
Editing * editing_get(const Scene *scene)
Definition sequencer.cc:286
int time_left_handle_frame_get(const Scene *, const Strip *strip)
const char * strip_give_name(const Strip *strip)
float time_start_frame_get(const Strip *strip)
bool transform_single_image_check(const Strip *strip)
Strip * select_active_get(const Scene *scene)
constexpr int MAX_CHANNELS
bool is_strip_connected(const Strip *strip)
bool transform_is_locked(ListBase *channels, const Strip *strip)
void thumbnail_cache_discard_requests_outside(Scene *scene, const rctf &rect)
ListBase * active_seqbase_get(const Editing *ed)
Definition sequencer.cc:433
ListBase * get_seqbase_from_strip(Strip *strip, ListBase **r_channels, int *r_offset)
eSeqOverlapMode tool_settings_overlap_mode_get(Scene *scene)
Definition sequencer.cc:421
void thumbnail_cache_maintain_capacity(Scene *scene)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
blender::VecBase< uint8_t, 4 > uchar4
VecBase< float, 2 > float2
const char * name
ARegionRuntimeHandle * runtime
char name[258]
Definition DNA_ID.h:432
struct Editing * ed
struct RenderData r
float * data
Definition BKE_sound.h:24
struct SequencerCacheOverlay cache_overlay
struct SequencerTimelineOverlay timeline_overlay
StripElem * stripdata
char dirpath[768]
char filename[256]
struct Object * scene_camera
struct Strip * input1
int8_t color_tag
struct Mask * mask
StripData * data
struct Scene * scene
struct MovieClip * clip
void * effectdata
struct bSound * sound
ListBase seqbase
StripRuntime runtime
float sound_offset
char name[64]
struct Strip * input2
unsigned char color[4]
char filepath[1024]
void * spinlock
void * waveform
double offset_time
ThemeStripColor strip_color[9]
blender::gpu::FrameBuffer * framebuffer_overlay
blender::Map< SeqRetimingKey *, Strip * > retiming_selection
float xmax
float xmin
float ymax
float ymin
i
Definition text_draw.cc:230
rcti ED_time_scrub_clamp_scroller_mask(const rcti &scroller_mask)
void ED_time_scrub_draw(const ARegion *region, const Scene *scene, bool display_seconds, bool discrete_frames, const int base)
void ED_time_scrub_draw_current_frame(const ARegion *region, const Scene *scene, bool display_seconds, bool display_stalk)
GPUViewport * WM_draw_region_get_viewport(ARegion *region)
Definition wm_draw.cc:940
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
void WM_gizmomap_draw(wmGizmoMap *gzmap, const bContext *C, const eWM_GizmoFlagMapDrawStep drawstep)
void wmOrtho2_region_pixelspace(const ARegion *region)