Blender V4.3
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
10#include <cmath>
11#include <cstring>
12
13#include "BLI_array.hh"
14#include "BLI_blenlib.h"
15#include "BLI_string_utils.hh"
16#include "BLI_task.hh"
17#include "BLI_threads.h"
18#include "BLI_utildefines.h"
19
20#include "DNA_scene_types.h"
21#include "DNA_screen_types.h"
22#include "DNA_sound_types.h"
23#include "DNA_space_types.h"
24#include "DNA_userdef_types.h"
25
26#include "BKE_context.hh"
27#include "BKE_fcurve.hh"
28#include "BKE_global.hh"
29#include "BKE_sound.h"
30
31#include "ED_anim_api.hh"
32#include "ED_markers.hh"
33#include "ED_mask.hh"
34#include "ED_sequencer.hh"
35#include "ED_space_api.hh"
36#include "ED_time_scrub_ui.hh"
37
38#include "GPU_matrix.hh"
39
40#include "IMB_imbuf.hh"
41
42#include "RNA_prototypes.hh"
43
44#include "SEQ_channels.hh"
45#include "SEQ_connect.hh"
46#include "SEQ_effects.hh"
47#include "SEQ_prefetch.hh"
48#include "SEQ_relations.hh"
49#include "SEQ_render.hh"
50#include "SEQ_retiming.hh"
51#include "SEQ_select.hh"
52#include "SEQ_sequencer.hh"
54#include "SEQ_time.hh"
55#include "SEQ_transform.hh"
56#include "SEQ_utils.hh"
57
58#include "UI_interface_icons.hh"
59#include "UI_resources.hh"
60#include "UI_view2d.hh"
61
62#include "WM_api.hh"
63#include "WM_types.hh"
64
65#include "BLF_api.hh"
66
67#include "MEM_guardedalloc.h"
68
69/* Own include. */
70#include "sequencer_intern.hh"
73
74using namespace blender;
75using namespace blender::ed::seq;
76
77constexpr int MUTE_ALPHA = 120;
78
79constexpr float ICON_SIZE = 12.0f;
80
85
87{
88 const Editing *ed = SEQ_editing_get(scene);
89 Vector<Sequence *> strips;
90
91 LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) {
93 v2d->cur.xmax)
94 {
95 continue;
96 }
98 SEQ_time_content_end_frame_get(scene, seq)) < v2d->cur.xmin)
99 {
100 continue;
101 }
102 if (seq->machine + 1.0f < v2d->cur.ymin) {
103 continue;
104 }
105 if (seq->machine > v2d->cur.ymax) {
106 continue;
107 }
108 strips.append(seq);
109 }
110 return strips;
111}
112
114{
116
117 ctx.C = C;
118 ctx.region = CTX_wm_region(C);
119 ctx.scene = CTX_data_scene(C);
120 ctx.sseq = CTX_wm_space_seq(C);
121 ctx.v2d = UI_view2d_fromcontext(C);
122
123 ctx.ed = SEQ_editing_get(ctx.scene);
124 ctx.channels = ctx.ed ? SEQ_channels_displayed_get(ctx.ed) : nullptr;
125
128
129 ctx.pixely = BLI_rctf_size_y(&ctx.v2d->cur) / BLI_rcti_size_y(&ctx.v2d->mask);
130 ctx.pixelx = BLI_rctf_size_x(&ctx.v2d->cur) / BLI_rcti_size_x(&ctx.v2d->mask);
131
133
134 ctx.quads = quads_batch;
135
136 return ctx;
137}
138
139static bool seq_draw_waveforms_poll(const SpaceSeq *sseq, const Sequence *seq)
140{
141 const bool strip_is_valid = seq->type == SEQ_TYPE_SOUND_RAM && seq->sound != nullptr;
142 const bool overlays_enabled = (sseq->flag & SEQ_SHOW_OVERLAY) != 0;
143 const bool ovelay_option = ((sseq->timeline_overlay.flag & SEQ_TIMELINE_ALL_WAVEFORMS) != 0 ||
145
147 return false;
148 }
149
150 if (strip_is_valid && overlays_enabled && ovelay_option) {
151 return true;
152 }
153
154 return false;
155}
156
158 const StripDrawContext *strip_ctx)
159{
160 return seq_draw_waveforms_poll(ctx->sseq, strip_ctx->seq) ||
161 strip_ctx->seq->type == SEQ_TYPE_COLOR;
162}
163
165 StripDrawContext *strip_ctx)
166{
167 float threshold = 8 * UI_SCALE_FAC;
168 if (strip_hides_text_overlay_first(ctx, strip_ctx)) {
169 threshold = 20 * UI_SCALE_FAC;
170 }
171
172 const bool overlays_enabled = (ctx->sseq->timeline_overlay.flag &
175
176 strip_ctx->can_draw_text_overlay = (strip_ctx->top - strip_ctx->bottom) / ctx->pixely >=
177 threshold;
178 strip_ctx->can_draw_text_overlay &= overlays_enabled;
179}
180
182 StripDrawContext *strip_ctx)
183{
184 float threshold = 20 * UI_SCALE_FAC;
185 if (strip_hides_text_overlay_first(ctx, strip_ctx)) {
186 threshold = 8 * UI_SCALE_FAC;
187 }
188
189 strip_ctx->can_draw_strip_content = ((strip_ctx->top - strip_ctx->bottom) / ctx->pixely) >
190 threshold;
191}
192
194 StripDrawContext *strip_ctx)
195{
196 float2 threshold{15 * UI_SCALE_FAC, 25 * UI_SCALE_FAC};
197 strip_ctx->can_draw_retiming_overlay = (strip_ctx->top - strip_ctx->bottom) / ctx->pixely >=
198 threshold.y;
199 strip_ctx->can_draw_retiming_overlay &= strip_ctx->strip_length / ctx->pixelx >= threshold.x;
201}
202
204{
205 using namespace seq;
206 StripDrawContext strip_ctx;
207 Scene *scene = ctx->scene;
208
209 strip_ctx.seq = seq;
210 strip_ctx.bottom = seq->machine + SEQ_STRIP_OFSBOTTOM;
211 strip_ctx.top = seq->machine + SEQ_STRIP_OFSTOP;
212 strip_ctx.left_handle = SEQ_time_left_handle_frame_get(scene, seq);
213 strip_ctx.right_handle = SEQ_time_right_handle_frame_get(scene, seq);
215 strip_ctx.content_end = SEQ_time_content_end_frame_get(scene, seq);
216
217 if (seq->type == SEQ_TYPE_SOUND_RAM && seq->sound != nullptr) {
218 /* Visualize sub-frame sound offsets. */
219 const double sound_offset = (seq->sound->offset_time + seq->sound_offset) * FPS;
220 strip_ctx.content_start += sound_offset;
221 strip_ctx.content_end += sound_offset;
222 }
223
224 /* Limit body to strip bounds. */
225 strip_ctx.content_start = min_ff(strip_ctx.content_start, strip_ctx.right_handle);
226 strip_ctx.content_end = max_ff(strip_ctx.content_end, strip_ctx.left_handle);
227
228 strip_ctx.strip_length = strip_ctx.right_handle - strip_ctx.left_handle;
229
233 strip_ctx.strip_is_too_small = (!strip_ctx.can_draw_text_overlay &&
234 !strip_ctx.can_draw_strip_content);
235 strip_ctx.is_active_strip = seq == SEQ_select_active_get(scene);
237 strip_ctx.handle_width = sequence_handle_size_get_clamped(ctx->scene, seq, ctx->pixelx);
240
241 /* Determine if strip (or contents of meta strip) has missing data/media. */
243 strip_ctx.missing_media = media_presence_is_missing(scene, seq);
244 strip_ctx.is_connected = SEQ_is_strip_connected(seq);
245 if (seq->type == SEQ_TYPE_META) {
246 const ListBase *seqbase = &seq->seqbase;
247 LISTBASE_FOREACH (const Sequence *, sub, seqbase) {
248 if (!SEQ_sequence_has_valid_data(sub)) {
249 strip_ctx.missing_data_block = true;
250 }
251 if (media_presence_is_missing(scene, sub)) {
252 strip_ctx.missing_media = true;
253 }
254 }
255 }
256
257 if (strip_ctx.can_draw_text_overlay) {
258 strip_ctx.strip_content_top = strip_ctx.top - min_ff(0.40f, 20 * UI_SCALE_FAC * ctx->pixely);
259 }
260 else {
261 strip_ctx.strip_content_top = strip_ctx.top;
262 }
263
264 strip_ctx.is_muted = SEQ_render_is_muted(ctx->channels, seq);
265 strip_ctx.curve = nullptr;
266 return strip_ctx;
267}
268
270 StripDrawContext &strip_ctx)
271{
272 strip_ctx.curve = nullptr;
273 const bool showing_curve_overlay = strip_ctx.can_draw_strip_content &&
274 (ctx->sseq->flag & SEQ_SHOW_OVERLAY) != 0 &&
275 (ctx->sseq->timeline_overlay.flag &
277 const bool showing_waveform = (strip_ctx.seq->type == SEQ_TYPE_SOUND_RAM) &&
278 !strip_ctx.strip_is_too_small &&
279 seq_draw_waveforms_poll(ctx->sseq, strip_ctx.seq);
280 if (showing_curve_overlay || showing_waveform) {
281 const char *prop_name = strip_ctx.seq->type == SEQ_TYPE_SOUND_RAM ? "volume" : "blend_alpha";
282 strip_ctx.curve = id_data_find_fcurve(
283 &ctx->scene->id, strip_ctx.seq, &RNA_Sequence, prop_name, 0, nullptr);
284 if (strip_ctx.curve && BKE_fcurve_is_empty(strip_ctx.curve)) {
285 strip_ctx.curve = nullptr;
286 }
287 }
288}
289
290static void color3ubv_from_seq(const Scene *curscene,
291 const Sequence *seq,
292 const bool show_strip_color_tag,
293 const bool is_muted,
294 uchar r_col[3])
295{
296 if (show_strip_color_tag && uint(seq->color_tag) < SEQUENCE_COLOR_TOT &&
298 {
299 bTheme *btheme = UI_GetTheme();
300 const ThemeStripColor *strip_color = &btheme->strip_color[seq->color_tag];
301 copy_v3_v3_uchar(r_col, strip_color->color);
302 return;
303 }
304
305 uchar blendcol[3];
306
307 /* Sometimes the active theme is not the sequencer theme, e.g. when an operator invokes the file
308 * browser. This makes sure we get the right color values for the theme. */
309 bThemeState theme_state;
310 UI_Theme_Store(&theme_state);
312
313 switch (seq->type) {
314 case SEQ_TYPE_IMAGE:
316 break;
317
318 case SEQ_TYPE_META:
320 break;
321
322 case SEQ_TYPE_MOVIE:
324 break;
325
328 break;
329
330 case SEQ_TYPE_MASK:
332 break;
333
334 case SEQ_TYPE_SCENE:
336
337 if (seq->scene == curscene) {
338 UI_GetColorPtrShade3ubv(r_col, 20, r_col);
339 }
340 break;
341
342 /* Transitions use input colors, fallback for when the input is a transition itself. */
343 case SEQ_TYPE_CROSS:
345 case SEQ_TYPE_WIPE:
347
348 /* Slightly offset hue to distinguish different transition types. */
349 if (seq->type == SEQ_TYPE_GAMCROSS) {
351 }
352 else if (seq->type == SEQ_TYPE_WIPE) {
354 }
355 break;
356
357 /* Effects. */
359 case SEQ_TYPE_SPEED:
360 case SEQ_TYPE_ADD:
361 case SEQ_TYPE_SUB:
362 case SEQ_TYPE_MUL:
366 case SEQ_TYPE_GLOW:
372
373 /* Slightly offset hue to distinguish different effects. */
374 if (seq->type == SEQ_TYPE_ADD) {
376 }
377 else if (seq->type == SEQ_TYPE_SUB) {
379 }
380 else if (seq->type == SEQ_TYPE_MUL) {
382 }
383 else if (seq->type == SEQ_TYPE_ALPHAOVER) {
385 }
386 else if (seq->type == SEQ_TYPE_ALPHAUNDER) {
388 }
389 else if (seq->type == SEQ_TYPE_OVERDROP) {
391 }
392 else if (seq->type == SEQ_TYPE_COLORMIX) {
394 }
395 else if (seq->type == SEQ_TYPE_GAUSSIAN_BLUR) {
397 }
398 else if (seq->type == SEQ_TYPE_GLOW) {
400 }
401 else if (seq->type == SEQ_TYPE_ADJUSTMENT) {
403 }
404 else if (seq->type == SEQ_TYPE_SPEED) {
406 }
407 else if (seq->type == SEQ_TYPE_TRANSFORM) {
409 }
410 else if (seq->type == SEQ_TYPE_MULTICAM) {
412 }
413 break;
414
415 case SEQ_TYPE_COLOR:
417 break;
418
421 blendcol[0] = blendcol[1] = blendcol[2] = 128;
422 if (is_muted) {
423 UI_GetColorPtrBlendShade3ubv(r_col, blendcol, 0.5, 20, r_col);
424 }
425 break;
426
427 case SEQ_TYPE_TEXT:
429 break;
430
431 default:
432 r_col[0] = 10;
433 r_col[1] = 255;
434 r_col[2] = 40;
435 break;
436 }
437
438 UI_Theme_Restore(&theme_state);
439}
440
441static void waveform_job_start_if_needed(const bContext *C, const Sequence *seq)
442{
443 bSound *sound = seq->sound;
444
445 BLI_spin_lock(static_cast<SpinLock *>(sound->spinlock));
446 if (!sound->waveform) {
447 /* Load the waveform data if it hasn't been loaded and cached already. */
448 if (!(sound->tags & SOUND_TAGS_WAVEFORM_LOADING)) {
449 /* Prevent sounds from reloading. */
451 BLI_spin_unlock(static_cast<SpinLock *>(sound->spinlock));
453 }
454 else {
455 BLI_spin_unlock(static_cast<SpinLock *>(sound->spinlock));
456 }
457 }
458 BLI_spin_unlock(static_cast<SpinLock *>(sound->spinlock));
459}
460
461static float align_frame_with_pixel(float frame_coord, float frames_per_pixel)
462{
463 return round_fl_to_int(frame_coord / frames_per_pixel) * frames_per_pixel;
464}
465
467 const StripDrawContext *strip_ctx)
468{
469 if (!seq_draw_waveforms_poll(timeline_ctx->sseq, strip_ctx->seq) ||
470 strip_ctx->strip_is_too_small)
471 {
472 return;
473 }
474
475 const View2D *v2d = timeline_ctx->v2d;
476 Scene *scene = timeline_ctx->scene;
477 Sequence *seq = strip_ctx->seq;
478
479 const bool half_style = (timeline_ctx->sseq->timeline_overlay.flag &
481
482 const float frames_per_pixel = BLI_rctf_size_x(&v2d->cur) / timeline_ctx->region->winx;
483 const float samples_per_frame = SOUND_WAVE_SAMPLES_PER_SECOND / FPS;
484 const float samples_per_pixel = samples_per_frame * frames_per_pixel;
485 const float bottom = strip_ctx->bottom + timeline_ctx->pixely * 2.0f;
486 const float top = strip_ctx->strip_content_top;
487 /* The y coordinate of signal level zero. */
488 const float y_zero = half_style ? bottom : (bottom + top) / 2.0f;
489 /* The y range of unit signal level. */
490 const float y_scale = half_style ? top - bottom : (top - bottom) / 2.0f;
491
492 /* Align strip start with nearest pixel to prevent waveform flickering. */
493 const float strip_start_aligned = align_frame_with_pixel(
494 strip_ctx->left_handle + timeline_ctx->pixelx * 3.0f, frames_per_pixel);
495 /* Offset x1 and x2 values, to match view min/max, if strip is out of bounds. */
496 const float draw_start_frame = max_ff(v2d->cur.xmin, strip_start_aligned);
497 const float draw_end_frame = min_ff(v2d->cur.xmax,
498 strip_ctx->right_handle - timeline_ctx->pixelx * 3.0f);
499 /* Offset must be also aligned, otherwise waveform flickers when moving left handle. */
500 float sample_start_frame = draw_start_frame -
501 (seq->sound->offset_time + seq->sound_offset) * FPS;
502
503 const int pixels_to_draw = round_fl_to_int((draw_end_frame - draw_start_frame) /
504 frames_per_pixel);
505
506 if (pixels_to_draw < 2) {
507 return; /* Not much to draw, exit before running job. */
508 }
509
510 waveform_job_start_if_needed(timeline_ctx->C, seq);
511
512 SoundWaveform *waveform = static_cast<SoundWaveform *>(seq->sound->waveform);
513 if (waveform == nullptr || waveform->length == 0) {
514 return; /* Waveform was not built. */
515 }
516
517 /* Draw zero line (when actual samples close to zero are drawn, they might not cover a pixel. */
518 uchar color[4] = {255, 255, 255, 127};
519 uchar color_clip[4] = {255, 0, 0, 127};
520 uchar color_rms[4] = {255, 255, 255, 204};
521 timeline_ctx->quads->add_line(draw_start_frame, y_zero, draw_end_frame, y_zero, color);
522
523 float prev_y_mid = y_zero;
524 for (int i = 0; i < pixels_to_draw; i++) {
525 float timeline_frame = sample_start_frame + i * frames_per_pixel;
526 float frame_index = SEQ_give_frame_index(scene, seq, timeline_frame) + seq->anim_startofs;
527 float sample = frame_index * samples_per_frame;
528 int sample_index = round_fl_to_int(sample);
529
530 if (sample_index < 0) {
531 continue;
532 }
533
534 if (sample_index >= waveform->length) {
535 break;
536 }
537
538 float value_min = waveform->data[sample_index * 3];
539 float value_max = waveform->data[sample_index * 3 + 1];
540 float rms = waveform->data[sample_index * 3 + 2];
541
542 if (samples_per_pixel > 1.0f) {
543 /* We need to sum up the values we skip over until the next step. */
544 float next_pos = sample + samples_per_pixel;
545 int end_idx = round_fl_to_int(next_pos);
546
547 for (int j = sample_index + 1; (j < waveform->length) && (j < end_idx); j++) {
548 value_min = min_ff(value_min, waveform->data[j * 3]);
549 value_max = max_ff(value_max, waveform->data[j * 3 + 1]);
550 rms = max_ff(rms, waveform->data[j * 3 + 2]);
551 }
552 }
553
554 float volume = seq->volume;
555 if (strip_ctx->curve != nullptr) {
556 float evaltime = draw_start_frame + (i * frames_per_pixel);
557 volume = evaluate_fcurve(strip_ctx->curve, evaltime);
558 CLAMP_MIN(volume, 0.0f);
559 }
560
561 value_min *= volume;
562 value_max *= volume;
563 rms *= volume;
564
565 bool is_clipping = false;
566 float clamped_min = clamp_f(value_min, -1.0f, 1.0f);
567 float clamped_max = clamp_f(value_max, -1.0f, 1.0f);
568 if (clamped_min != value_min || clamped_max != value_max) {
569 is_clipping = true;
570 }
571 value_min = clamped_min;
572 value_max = clamped_max;
573
574 /* We are drawing only half to the waveform, mirroring the lower part upwards.
575 * If both min and max are on the same side of zero line, we want to draw a bar
576 * between them. If min and max cross zero, we want to fill bar from zero to max
577 * of those. */
578 if (half_style) {
579 bool pos_min = value_min > 0.0f;
580 bool pos_max = value_max > 0.0f;
581 float abs_min = std::abs(value_min);
582 float abs_max = std::abs(value_max);
583 if (pos_min == pos_max) {
584 value_min = std::min(abs_min, abs_max);
585 value_max = std::max(abs_min, abs_max);
586 }
587 else {
588 value_min = 0;
589 value_max = std::max(abs_min, abs_max);
590 }
591 }
592
593 float x1 = draw_start_frame + i * frames_per_pixel;
594 float x2 = draw_start_frame + (i + 1) * frames_per_pixel;
595 float y_min = y_zero + value_min * y_scale;
596 float y_max = y_zero + value_max * y_scale;
597 float y_mid = (y_max + y_min) * 0.5f;
598
599 /* If a bar would be below 2px, make it a line. */
600 if (y_max - y_min < timeline_ctx->pixely * 2) {
601 /* If previous segment was also a line of different enough
602 * height, join them. */
603 if (std::abs(y_mid - prev_y_mid) > timeline_ctx->pixely) {
604 float x0 = draw_start_frame + (i - 1) * frames_per_pixel;
605 timeline_ctx->quads->add_line(x0, prev_y_mid, x1, y_mid, is_clipping ? color_clip : color);
606 }
607 timeline_ctx->quads->add_line(x1, y_mid, x2, y_mid, is_clipping ? color_clip : color);
608 }
609 else {
610 float rms_min = y_zero + max_ff(-rms, value_min) * y_scale;
611 float rms_max = y_zero + min_ff(rms, value_max) * y_scale;
612 /* RMS */
613 timeline_ctx->quads->add_quad(
614 x1, rms_min, x2, rms_max, is_clipping ? color_clip : color_rms);
615 /* Sample */
616 timeline_ctx->quads->add_quad(x1, y_min, x2, y_max, is_clipping ? color_clip : color);
617 }
618
619 prev_y_mid = y_mid;
620 }
621}
622
623static void drawmeta_contents(TimelineDrawContext *timeline_ctx,
624 const StripDrawContext *strip_ctx,
625 float corner_radius)
626{
627 using namespace seq;
628 Sequence *seq_meta = strip_ctx->seq;
629 if (!strip_ctx->can_draw_strip_content || (timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) == 0) {
630 return;
631 }
632 if ((seq_meta->type != SEQ_TYPE_META) &&
633 ((seq_meta->type != SEQ_TYPE_SCENE) || (seq_meta->flag & SEQ_SCENE_STRIPS) == 0))
634 {
635 return;
636 }
637
638 Scene *scene = timeline_ctx->scene;
639
640 uchar col[4];
641
642 int chan_min = SEQ_MAX_CHANNELS;
643 int chan_max = 0;
644 int chan_range = 0;
645 /* Some vertical margin to account for rounded corners, so that contents do
646 * not draw outside them. Can be removed when meta contents are drawn with
647 * full rounded corners masking shader. */
648 const float bottom = strip_ctx->bottom + corner_radius * 0.8f * timeline_ctx->pixely;
649 const float top = strip_ctx->strip_content_top - corner_radius * 0.8f * timeline_ctx->pixely;
650 const float draw_range = top - bottom;
651 if (draw_range < timeline_ctx->pixely) {
652 return;
653 }
654 float draw_height;
655
656 ListBase *meta_seqbase;
657 ListBase *meta_channels;
658 int offset;
659
660 meta_seqbase = SEQ_get_seqbase_from_sequence(seq_meta, &meta_channels, &offset);
661
662 if (!meta_seqbase || BLI_listbase_is_empty(meta_seqbase)) {
663 return;
664 }
665
666 if (seq_meta->type == SEQ_TYPE_SCENE) {
667 offset = seq_meta->start - offset;
668 }
669 else {
670 offset = 0;
671 }
672
673 LISTBASE_FOREACH (Sequence *, seq, meta_seqbase) {
674 chan_min = min_ii(chan_min, seq->machine);
675 chan_max = max_ii(chan_max, seq->machine);
676 }
677
678 chan_range = (chan_max - chan_min) + 1;
679 draw_height = draw_range / chan_range;
680
681 col[3] = 196; /* Alpha, used for all meta children. */
682
683 const float meta_x1 = strip_ctx->left_handle;
684 const float meta_x2 = strip_ctx->right_handle;
685
686 /* Draw only immediate children (1 level depth). */
687 LISTBASE_FOREACH (Sequence *, seq, meta_seqbase) {
688 float x1_chan = SEQ_time_left_handle_frame_get(scene, seq) + offset;
689 float x2_chan = SEQ_time_right_handle_frame_get(scene, seq) + offset;
690 if (x1_chan <= meta_x2 && x2_chan >= meta_x1) {
691 float y_chan = (seq->machine - chan_min) / float(chan_range) * draw_range;
692 float y1_chan, y2_chan;
693
694 if (seq->type == SEQ_TYPE_COLOR) {
695 SolidColorVars *colvars = (SolidColorVars *)seq->effectdata;
696 rgb_float_to_uchar(col, colvars->col);
697 }
698 else {
699 color3ubv_from_seq(scene, seq, strip_ctx->show_strip_color_tag, strip_ctx->is_muted, col);
700 }
701
702 if (strip_ctx->is_muted || SEQ_render_is_muted(meta_channels, seq)) {
703 col[3] = 64;
704 }
705 else {
706 col[3] = 196;
707 }
708
709 const bool missing_data = !SEQ_sequence_has_valid_data(seq);
710 const bool missing_media = media_presence_is_missing(scene, seq);
711 if (missing_data || missing_media) {
712 col[0] = 112;
713 col[1] = 0;
714 col[2] = 0;
715 }
716
717 /* Clamp within parent sequence strip bounds. */
718 x1_chan = max_ff(x1_chan, meta_x1);
719 x2_chan = min_ff(x2_chan, meta_x2);
720
721 y1_chan = bottom + y_chan + (draw_height * SEQ_STRIP_OFSBOTTOM);
722 y2_chan = bottom + y_chan + (draw_height * SEQ_STRIP_OFSTOP);
723
724 timeline_ctx->quads->add_quad(x1_chan, y1_chan, x2_chan, y2_chan, col);
725 }
726 }
727}
728
729static void draw_handle_transform_text(const TimelineDrawContext *timeline_ctx,
730 const StripDrawContext *strip_ctx,
731 eSeqHandle handle)
732{
733 /* Draw numbers for start and end of the strip next to its handles. */
734 if (strip_ctx->strip_is_too_small || (strip_ctx->seq->flag & SELECT) == 0) {
735 return;
736 }
737
738 if (ED_sequencer_handle_is_selected(strip_ctx->seq, handle) == 0 &&
739 (G.moving & G_TRANSFORM_SEQ) == 0)
740 {
741 return;
742 }
743
744 char numstr[64];
746
747 /* Calculate if strip is wide enough for showing the labels. */
748 size_t numstr_len = SNPRINTF_RLEN(
749 numstr, "%d%d", int(strip_ctx->left_handle), int(strip_ctx->right_handle));
750 const float tot_width = BLF_width(BLF_default(), numstr, numstr_len);
751
752 if (strip_ctx->strip_length / timeline_ctx->pixelx < 20 + tot_width) {
753 return;
754 }
755
756 const uchar col[4] = {255, 255, 255, 255};
757 const float text_margin = 1.2f * strip_ctx->handle_width;
758 const float text_y = strip_ctx->bottom + 0.09f;
759 float text_x = strip_ctx->left_handle;
760
761 if (handle == SEQ_HANDLE_LEFT) {
762 numstr_len = SNPRINTF_RLEN(numstr, "%d", int(strip_ctx->left_handle));
763 text_x += text_margin;
764 }
765 else {
766 numstr_len = SNPRINTF_RLEN(numstr, "%d", int(strip_ctx->right_handle - 1));
767 text_x = strip_ctx->right_handle -
768 (text_margin + timeline_ctx->pixelx * BLF_width(BLF_default(), numstr, numstr_len));
769 }
770 UI_view2d_text_cache_add(timeline_ctx->v2d, text_x, text_y, numstr, numstr_len, col);
771}
772
773float sequence_handle_size_get_clamped(const Scene *scene, Sequence *seq, const float pixelx)
774{
775 const bool use_thin_handle = (U.sequencer_editor_flag & USER_SEQ_ED_SIMPLE_TWEAKING) != 0;
776 const float handle_size = use_thin_handle ? 5.0f : 8.0f;
777 const float maxhandle = (pixelx * handle_size) * U.pixelsize;
778
779 /* Ensure that handle is not wider, than quarter of strip. */
780 return min_ff(maxhandle,
781 (float(SEQ_time_right_handle_frame_get(scene, seq) -
782 SEQ_time_left_handle_frame_get(scene, seq)) /
783 4.0f));
784}
785
786static const char *draw_seq_text_get_name(const Sequence *seq)
787{
788 const char *name = seq->name + 2;
789 if (name[0] == '\0') {
790 name = SEQ_sequence_give_name(seq);
791 }
792 return name;
793}
794
795static void draw_seq_text_get_source(const Sequence *seq, char *r_source, size_t source_maxncpy)
796{
797 *r_source = '\0';
798
799 /* Set source for the most common types. */
800 switch (seq->type) {
801 case SEQ_TYPE_IMAGE:
802 case SEQ_TYPE_MOVIE: {
804 r_source, source_maxncpy, seq->strip->dirpath, seq->strip->stripdata->filename);
805 break;
806 }
807 case SEQ_TYPE_SOUND_RAM: {
808 if (seq->sound != nullptr) {
809 BLI_strncpy(r_source, seq->sound->filepath, source_maxncpy);
810 }
811 break;
812 }
813 case SEQ_TYPE_MULTICAM: {
814 BLI_snprintf(r_source, source_maxncpy, "Channel: %d", seq->multicam_source);
815 break;
816 }
817 case SEQ_TYPE_TEXT: {
818 const TextVars *textdata = static_cast<TextVars *>(seq->effectdata);
819 BLI_strncpy(r_source, textdata->text, source_maxncpy);
820 break;
821 }
822 case SEQ_TYPE_SCENE: {
823 if (seq->scene != nullptr) {
824 if (seq->scene_camera != nullptr) {
825 BLI_snprintf(r_source,
826 source_maxncpy,
827 "%s (%s)",
828 seq->scene->id.name + 2,
829 seq->scene_camera->id.name + 2);
830 }
831 else {
832 BLI_strncpy(r_source, seq->scene->id.name + 2, source_maxncpy);
833 }
834 }
835 break;
836 }
837 case SEQ_TYPE_MOVIECLIP: {
838 if (seq->clip != nullptr) {
839 BLI_strncpy(r_source, seq->clip->id.name + 2, source_maxncpy);
840 }
841 break;
842 }
843 case SEQ_TYPE_MASK: {
844 if (seq->mask != nullptr) {
845 BLI_strncpy(r_source, seq->mask->id.name + 2, source_maxncpy);
846 }
847 break;
848 }
849 }
850}
851
853 const StripDrawContext *strip_ctx,
854 char *r_overlay_string,
855 size_t overlay_string_len)
856{
857 const Sequence *seq = strip_ctx->seq;
858
859 const char *text_sep = " | ";
860 const char *text_array[5];
861 int i = 0;
862
864 text_array[i++] = draw_seq_text_get_name(seq);
865 }
866
867 char source[FILE_MAX];
869 draw_seq_text_get_source(seq, source, sizeof(source));
870 if (source[0] != '\0') {
871 if (i != 0) {
872 text_array[i++] = text_sep;
873 }
874 text_array[i++] = source;
875 }
876 }
877
878 char strip_duration_text[16];
880 SNPRINTF(strip_duration_text, "%d", int(strip_ctx->strip_length));
881 if (i != 0) {
882 text_array[i++] = text_sep;
883 }
884 text_array[i++] = strip_duration_text;
885 }
886
887 BLI_assert(i <= ARRAY_SIZE(text_array));
888
889 return BLI_string_join_array(r_overlay_string, overlay_string_len, text_array, i);
890}
891
892static void get_strip_text_color(const StripDrawContext *strip, uchar r_col[4])
893{
894 const Sequence *seq = strip->seq;
895 const bool active_or_selected = (seq->flag & SELECT) || strip->is_active_strip;
896
897 /* Text: white when selected/active, black otherwise. */
898 r_col[0] = r_col[1] = r_col[2] = r_col[3] = 255;
899
900 /* If not active or selected, draw text black. */
901 if (!active_or_selected) {
902 r_col[0] = r_col[1] = r_col[2] = 0;
903
904 /* On muted and missing media/data-block strips: gray color, reduce opacity. */
905 if (strip->is_muted || strip->missing_data_block || strip->missing_media) {
906 r_col[0] = r_col[1] = r_col[2] = 192;
907 r_col[3] *= 0.66f;
908 }
909 }
910}
911
913 const rctf &rect,
914 int icon_id,
915 const uchar color[4])
916{
919
920 const float icon_size = ICON_SIZE * UI_SCALE_FAC;
921 if (BLI_rctf_size_x(&rect) * 1.1f < icon_size * ctx.pixelx ||
922 BLI_rctf_size_y(&rect) * 1.1f < icon_size * ctx.pixely)
923 {
925 return;
926 }
927
928 const float left = ((rect.xmin - ctx.v2d->cur.xmin) / ctx.pixelx);
929 const float right = ((rect.xmax - ctx.v2d->cur.xmin) / ctx.pixelx);
930 const float bottom = ((rect.ymin - ctx.v2d->cur.ymin) / ctx.pixely);
931 const float top = ((rect.ymax - ctx.v2d->cur.ymin) / ctx.pixely);
932 const float x_offset = (right - left - icon_size) * 0.5f;
933 const float y_offset = (top - bottom - icon_size) * 0.5f;
934
935 const float inv_scale_fac = (ICON_DEFAULT_HEIGHT / ICON_SIZE) * UI_INV_SCALE_FAC;
936
937 UI_icon_draw_ex(left + x_offset,
938 bottom + y_offset,
939 icon_id,
940 inv_scale_fac,
941 1.0f,
942 0.0f,
943 color,
944 false,
946
947 /* Restore view matrix. */
949}
950
951static void draw_strip_icons(TimelineDrawContext *timeline_ctx,
952 const Vector<StripDrawContext> &strips)
953{
954 const float icon_size_x = ICON_SIZE * timeline_ctx->pixelx * UI_SCALE_FAC;
955
956 for (const StripDrawContext &strip : strips) {
957 const bool missing_data = strip.missing_data_block;
958 const bool missing_media = strip.missing_media;
959 const bool is_connected = strip.is_connected;
960 if (!missing_data && !missing_media && !is_connected) {
961 continue;
962 }
963
964 /* Draw icon in the title bar area. */
965 if ((timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) != 0 && !strip.strip_is_too_small &&
966 strip.can_draw_text_overlay)
967 {
968 uchar col[4];
969 get_strip_text_color(&strip, col);
970
971 float icon_indent = 2.0f * strip.handle_width - 4 * timeline_ctx->pixelx * UI_SCALE_FAC;
972 rctf rect;
973 rect.ymin = strip.strip_content_top;
974 rect.ymax = strip.top;
975 rect.xmin = max_ff(strip.left_handle, timeline_ctx->v2d->cur.xmin) + icon_indent;
976 if (missing_data) {
977 rect.xmax = min_ff(strip.right_handle - strip.handle_width, rect.xmin + icon_size_x);
978 draw_icon_centered(*timeline_ctx, rect, ICON_LIBRARY_DATA_BROKEN, col);
979 rect.xmin = rect.xmax;
980 }
981 if (missing_media) {
982 rect.xmax = min_ff(strip.right_handle - strip.handle_width, rect.xmin + icon_size_x);
983 draw_icon_centered(*timeline_ctx, rect, ICON_ERROR, col);
984 rect.xmin = rect.xmax;
985 }
986 if (is_connected) {
987 rect.xmax = min_ff(strip.right_handle - strip.handle_width, rect.xmin + icon_size_x);
988 draw_icon_centered(*timeline_ctx, rect, ICON_LINKED, col);
989 }
990 }
991
992 /* Draw icon in center of content. */
993 if (strip.can_draw_strip_content && strip.seq->type != SEQ_TYPE_META) {
994 rctf rect;
995 rect.xmin = strip.left_handle + strip.handle_width;
996 rect.xmax = strip.right_handle - strip.handle_width;
997 rect.ymin = strip.bottom;
998 rect.ymax = strip.strip_content_top;
999 uchar col[4] = {112, 0, 0, 255};
1000 if (missing_data) {
1001 draw_icon_centered(*timeline_ctx, rect, ICON_LIBRARY_DATA_BROKEN, col);
1002 }
1003 if (missing_media) {
1004 draw_icon_centered(*timeline_ctx, rect, ICON_ERROR, col);
1005 }
1006 }
1007 }
1008}
1009
1010/* Draw info text on a sequence strip. */
1012 const StripDrawContext *strip_ctx)
1013{
1014 if ((timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) == 0) {
1015 return;
1016 }
1017 /* Draw text only if there is enough horizontal or vertical space. */
1018 if ((strip_ctx->strip_length <= 32 * timeline_ctx->pixelx * UI_SCALE_FAC) ||
1019 strip_ctx->strip_is_too_small || !strip_ctx->can_draw_text_overlay)
1020 {
1021 return;
1022 }
1023
1024 char overlay_string[FILE_MAX];
1025 size_t overlay_string_len = draw_seq_text_get_overlay_string(
1026 timeline_ctx, strip_ctx, overlay_string, sizeof(overlay_string));
1027
1028 if (overlay_string_len == 0) {
1029 return;
1030 }
1031
1032 uchar col[4];
1033 get_strip_text_color(strip_ctx, col);
1034
1035 float text_margin = 2.0f * strip_ctx->handle_width;
1036 rctf rect;
1037 rect.xmin = strip_ctx->left_handle + text_margin;
1038 rect.xmax = strip_ctx->right_handle - text_margin;
1039 rect.ymax = strip_ctx->top;
1040 /* Depending on the vertical space, draw text on top or in the center of strip. */
1041 rect.ymin = !strip_ctx->can_draw_strip_content ? strip_ctx->bottom :
1042 strip_ctx->strip_content_top;
1043 rect.xmin = max_ff(rect.xmin, timeline_ctx->v2d->cur.xmin + text_margin);
1044 int num_icons = 0;
1045 if (strip_ctx->missing_data_block) {
1046 num_icons++;
1047 }
1048 if (strip_ctx->missing_media) {
1049 num_icons++;
1050 }
1051 if (strip_ctx->is_connected) {
1052 num_icons++;
1053 }
1054 rect.xmin += num_icons * ICON_SIZE * timeline_ctx->pixelx * UI_SCALE_FAC;
1055 rect.xmin = min_ff(rect.xmin, timeline_ctx->v2d->cur.xmax);
1056
1057 CLAMP(rect.xmax, timeline_ctx->v2d->cur.xmin + text_margin, timeline_ctx->v2d->cur.xmax);
1058 if (rect.xmin >= rect.xmax) { /* No space for label left. */
1059 return;
1060 }
1061
1063 timeline_ctx->v2d, &rect, overlay_string, overlay_string_len, col);
1064}
1065
1066static void draw_strip_offsets(TimelineDrawContext *timeline_ctx,
1067 const StripDrawContext *strip_ctx)
1068{
1069 const Sequence *seq = strip_ctx->seq;
1070 if ((timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) == 0) {
1071 return;
1072 }
1073 if (strip_ctx->is_single_image || timeline_ctx->pixely <= 0) {
1074 return;
1075 }
1076 if ((timeline_ctx->sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_OFFSETS) == 0 &&
1077 (strip_ctx->seq != ED_sequencer_special_preview_get()))
1078 {
1079 return;
1080 }
1081
1082 const Scene *scene = timeline_ctx->scene;
1083
1084 uchar col[4], blend_col[4];
1085 color3ubv_from_seq(scene, seq, strip_ctx->show_strip_color_tag, strip_ctx->is_muted, col);
1086 if (seq->flag & SELECT) {
1088 }
1089 col[3] = strip_ctx->is_muted ? MUTE_ALPHA : 200;
1090 UI_GetColorPtrShade3ubv(col, 10, blend_col);
1091 blend_col[3] = 255;
1092
1093 if (strip_ctx->left_handle > strip_ctx->content_start) {
1094 timeline_ctx->quads->add_quad(strip_ctx->left_handle,
1095 strip_ctx->bottom - timeline_ctx->pixely,
1096 strip_ctx->content_start,
1097 strip_ctx->bottom - SEQ_STRIP_OFSBOTTOM,
1098 col);
1099 timeline_ctx->quads->add_wire_quad(strip_ctx->left_handle,
1100 strip_ctx->bottom - timeline_ctx->pixely,
1101 strip_ctx->content_start,
1102 strip_ctx->bottom - SEQ_STRIP_OFSBOTTOM,
1103 blend_col);
1104 }
1105 if (strip_ctx->right_handle < strip_ctx->content_end) {
1106 timeline_ctx->quads->add_quad(strip_ctx->right_handle,
1107 strip_ctx->top + timeline_ctx->pixely,
1108 strip_ctx->content_end,
1109 strip_ctx->top + SEQ_STRIP_OFSBOTTOM,
1110 col);
1111 timeline_ctx->quads->add_wire_quad(strip_ctx->right_handle,
1112 strip_ctx->top + timeline_ctx->pixely,
1113 strip_ctx->content_end,
1114 strip_ctx->top + SEQ_STRIP_OFSBOTTOM,
1115 blend_col);
1116 }
1117}
1118
1125 const StripDrawContext *strip_ctx)
1126{
1127 if (!strip_ctx->can_draw_strip_content || (timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) == 0 ||
1128 (timeline_ctx->sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_FCURVES) == 0)
1129 {
1130 return;
1131 }
1132 if (strip_ctx->curve == nullptr) {
1133 return;
1134 }
1135
1136 const int eval_step = max_ii(1, floor(timeline_ctx->pixelx));
1137 uchar color[4] = {0, 0, 0, 38};
1138
1139 /* Clamp curve evaluation to the editor's borders. */
1140 int eval_start = max_ff(strip_ctx->left_handle, timeline_ctx->v2d->cur.xmin);
1141 int eval_end = min_ff(strip_ctx->right_handle, timeline_ctx->v2d->cur.xmax + 1);
1142 if (eval_start >= eval_end) {
1143 return;
1144 }
1145
1146 const float y_height = strip_ctx->top - strip_ctx->bottom;
1147 float prev_x = eval_start;
1148 float prev_val = evaluate_fcurve(strip_ctx->curve, eval_start);
1149 CLAMP(prev_val, 0.0f, 1.0f);
1150 bool skip = false;
1151
1152 for (int timeline_frame = eval_start + eval_step; timeline_frame <= eval_end;
1153 timeline_frame += eval_step)
1154 {
1155 float curve_val = evaluate_fcurve(strip_ctx->curve, timeline_frame);
1156 CLAMP(curve_val, 0.0f, 1.0f);
1157
1158 /* Avoid adding adjacent verts that have the same value. */
1159 if (curve_val == prev_val && timeline_frame < eval_end - eval_step) {
1160 skip = true;
1161 continue;
1162 }
1163
1164 /* If some frames were skipped above, we need to close the shape. */
1165 if (skip) {
1166 timeline_ctx->quads->add_quad(prev_x,
1167 (prev_val * y_height) + strip_ctx->bottom,
1168 prev_x,
1169 strip_ctx->top,
1170 timeline_frame - eval_step,
1171 (prev_val * y_height) + strip_ctx->bottom,
1172 timeline_frame - eval_step,
1173 strip_ctx->top,
1174 color);
1175 skip = false;
1176 prev_x = timeline_frame - eval_step;
1177 }
1178
1179 timeline_ctx->quads->add_quad(prev_x,
1180 (prev_val * y_height) + strip_ctx->bottom,
1181 prev_x,
1182 strip_ctx->top,
1183 timeline_frame,
1184 (curve_val * y_height) + strip_ctx->bottom,
1185 timeline_frame,
1186 strip_ctx->top,
1187 color);
1188 prev_x = timeline_frame;
1189 prev_val = curve_val;
1190 }
1191}
1192
1193/* When active strip is a Multi-cam strip, highlight its source channel. */
1195 const StripDrawContext *strip_ctx)
1196{
1197 Sequence *act_seq = SEQ_select_active_get(timeline_ctx->scene);
1198
1199 if (strip_ctx->seq != act_seq || act_seq == nullptr) {
1200 return;
1201 }
1202 if ((act_seq->flag & SELECT) == 0 || act_seq->type != SEQ_TYPE_MULTICAM) {
1203 return;
1204 }
1205
1206 int channel = act_seq->multicam_source;
1207
1208 if (channel == 0) {
1209 return;
1210 }
1211
1212 View2D *v2d = timeline_ctx->v2d;
1213 uchar color[4] = {255, 255, 255, 48};
1214 timeline_ctx->quads->add_quad(v2d->cur.xmin, channel, v2d->cur.xmax, channel + 1, color);
1215}
1216
1217/* Force redraw, when prefetching and using cache view. */
1218static void seq_prefetch_wm_notify(const bContext *C, Scene *scene)
1219{
1220 if (SEQ_prefetch_need_redraw(C, scene)) {
1222 }
1223}
1224
1226{
1227 View2D *v2d = ctx->v2d;
1233
1234 /* Alternating horizontal stripes. */
1235 int i = max_ii(1, int(v2d->cur.ymin) - 1);
1236 while (i < v2d->cur.ymax) {
1237 if (i & 1) {
1238 immRectf(pos, v2d->cur.xmin, i, v2d->cur.xmax, i + 1);
1239 }
1240 i++;
1241 }
1242
1245}
1246
1247/* Get visible strips into two sets: regular strips, and strips
1248 * that are dragged over other strips right now (e.g. dragging
1249 * selection in the timeline). This is to make the dragged strips
1250 * always render "on top" of others. */
1252 Vector<StripDrawContext> &r_bottom_layer,
1253 Vector<StripDrawContext> &r_top_layer)
1254{
1255 r_bottom_layer.clear();
1256 r_top_layer.clear();
1257
1258 Vector<Sequence *> strips = sequencer_visible_strips_get(timeline_ctx->C);
1259 r_bottom_layer.reserve(strips.size());
1260
1261 for (Sequence *seq : strips) {
1262 StripDrawContext strip_ctx = strip_draw_context_get(timeline_ctx, seq);
1263 if ((seq->flag & SEQ_OVERLAP) == 0) {
1264 r_bottom_layer.append(strip_ctx);
1265 }
1266 else {
1267 r_top_layer.append(strip_ctx);
1268 }
1269 }
1270
1271 /* Finding which curves (if any) drive a strip is expensive, do these lookups
1272 * in parallel. */
1273 threading::parallel_for(IndexRange(r_bottom_layer.size()), 64, [&](IndexRange range) {
1274 for (int64_t index : range) {
1275 strip_draw_context_curve_get(timeline_ctx, r_bottom_layer[index]);
1276 }
1277 });
1278 threading::parallel_for(IndexRange(r_top_layer.size()), 64, [&](IndexRange range) {
1279 for (int64_t index : range) {
1280 strip_draw_context_curve_get(timeline_ctx, r_top_layer[index]);
1281 }
1282 });
1283}
1284
1286 StripsDrawBatch &strips_batch,
1287 const Vector<StripDrawContext> &strips)
1288{
1290 wmOrtho2_region_pixelspace(timeline_ctx->region);
1291
1293
1294 const bool show_overlay = (timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) != 0;
1295 const Scene *scene = timeline_ctx->scene;
1296 for (const StripDrawContext &strip : strips) {
1297 SeqStripDrawData &data = strips_batch.add_strip(strip.content_start,
1298 strip.content_end,
1299 strip.top,
1300 strip.bottom,
1301 strip.strip_content_top,
1302 strip.left_handle,
1303 strip.right_handle,
1304 strip.handle_width,
1305 strip.is_single_image);
1306
1307 /* Background color. */
1308 uchar col[4];
1310 color3ubv_from_seq(scene, strip.seq, strip.show_strip_color_tag, strip.is_muted, col);
1311 col[3] = strip.is_muted ? MUTE_ALPHA : 255;
1312 /* Muted strips: turn almost gray. */
1313 if (strip.is_muted) {
1314 uchar muted_color[3] = {128, 128, 128};
1315 UI_GetColorPtrBlendShade3ubv(col, muted_color, 0.5f, 0, col);
1316 }
1317 data.col_background = color_pack(col);
1318
1319 /* Color band state. */
1320 if (show_overlay && (strip.seq->type == SEQ_TYPE_COLOR)) {
1321 data.flags |= GPU_SEQ_FLAG_COLOR_BAND;
1322 SolidColorVars *colvars = (SolidColorVars *)strip.seq->effectdata;
1323 rgb_float_to_uchar(col, colvars->col);
1324 data.col_color_band = color_pack(col);
1325 }
1326
1327 /* Transition state. */
1328 if (show_overlay && strip.can_draw_strip_content &&
1330 {
1331 data.flags |= GPU_SEQ_FLAG_TRANSITION;
1332
1333 const Sequence *seq1 = strip.seq->seq1;
1334 const Sequence *seq2 = strip.seq->seq2;
1335
1336 /* Left side. */
1337 if (seq1->type == SEQ_TYPE_COLOR) {
1338 rgb_float_to_uchar(col, ((const SolidColorVars *)seq1->effectdata)->col);
1339 }
1340 else {
1341 color3ubv_from_seq(scene, seq1, strip.show_strip_color_tag, strip.is_muted, col);
1342 }
1343 data.col_transition_in = color_pack(col);
1344
1345 /* Right side. */
1346 if (seq2->type == SEQ_TYPE_COLOR) {
1347 rgb_float_to_uchar(col, ((const SolidColorVars *)seq2->effectdata)->col);
1348 }
1349 else {
1350 color3ubv_from_seq(scene, seq2, strip.show_strip_color_tag, strip.is_muted, col);
1351 /* If the transition inputs are of the same type, draw the right side slightly darker. */
1352 if (seq1->type == seq2->type) {
1354 }
1355 }
1356 data.col_transition_out = color_pack(col);
1357 }
1358 }
1359 strips_batch.flush_batch();
1362}
1363
1365 SeqStripDrawData &data)
1366{
1367 if (strip.missing_data_block || strip.missing_media) {
1368 /* Do not tint title area for muted strips; we want to see gray for them. */
1369 if (!strip.is_muted) {
1370 data.flags |= GPU_SEQ_FLAG_MISSING_TITLE;
1371 }
1372 /* Do not tint content area for meta strips; we want to display children. */
1373 if (strip.seq->type != SEQ_TYPE_META) {
1374 data.flags |= GPU_SEQ_FLAG_MISSING_CONTENT;
1375 }
1376 }
1377}
1378
1380 const TimelineDrawContext *timeline_ctx,
1381 SeqStripDrawData &data)
1382{
1383 if (SEQ_transform_is_locked(timeline_ctx->channels, strip.seq)) {
1384 data.flags |= GPU_SEQ_FLAG_LOCKED;
1385 }
1386}
1387
1389 const TimelineDrawContext *timeline_ctx,
1390 SeqStripDrawData &data)
1391{
1392 const bool active = strip.is_active_strip;
1393 const bool selected = strip.seq->flag & SELECT;
1394 uchar4 col{0, 0, 0, 255};
1395
1396 if (selected) {
1398 data.flags |= GPU_SEQ_FLAG_SELECTED;
1399 }
1400 if (active) {
1401 if (selected) {
1403 }
1404 else {
1406 }
1407 data.flags |= GPU_SEQ_FLAG_ACTIVE;
1408 }
1409 if (!selected && !active) {
1410 /* Color for unselected strips is a bit darker than the background. */
1412 }
1413
1414 const eSeqOverlapMode overlap_mode = SEQ_tool_settings_overlap_mode_get(timeline_ctx->scene);
1415 const bool use_overwrite = overlap_mode == SEQ_OVERLAP_OVERWRITE;
1416 const bool overlaps = (strip.seq->flag & SEQ_OVERLAP) && (G.moving & G_TRANSFORM_SEQ);
1417
1418 /* Outline while translating strips:
1419 * - Slightly lighter.
1420 * - Red when overlapping with other strips. */
1421 if (G.moving & G_TRANSFORM_SEQ) {
1422 if (overlaps && !use_overwrite) {
1423 col[0] = 255;
1424 col[1] = col[2] = 33;
1425 data.flags |= GPU_SEQ_FLAG_OVERLAP;
1426 }
1427 else if (selected) {
1429 }
1430 }
1431
1432 data.col_outline = color_pack(col);
1433}
1434
1436 const TimelineDrawContext *timeline_ctx,
1437 SeqStripDrawData &data)
1438{
1439 const Sequence *act_seq = SEQ_select_active_get(timeline_ctx->scene);
1440 const Sequence *special_preview = ED_sequencer_special_preview_get();
1441 /* Highlight if strip is an input of an active strip, or if the strip is solo preview. */
1442 if (act_seq != nullptr && (act_seq->flag & SELECT) != 0) {
1443 if (act_seq->seq1 == strip.seq || act_seq->seq2 == strip.seq) {
1444 data.flags |= GPU_SEQ_FLAG_HIGHLIGHT;
1445 }
1446 }
1447 if (special_preview == strip.seq) {
1448 data.flags |= GPU_SEQ_FLAG_HIGHLIGHT;
1449 }
1450}
1451
1453 const TimelineDrawContext *timeline_ctx,
1454 SeqStripDrawData &data)
1455{
1456 const Scene *scene = timeline_ctx->scene;
1457 const bool selected = strip.seq->flag & SELECT;
1458 const bool show_handles = (U.sequencer_editor_flag & USER_SEQ_ED_SIMPLE_TWEAKING) == 0;
1459 /* Handles on left/right side. */
1460 if (!SEQ_transform_is_locked(timeline_ctx->channels, strip.seq) &&
1461 ED_sequencer_can_select_handle(scene, strip.seq, timeline_ctx->v2d))
1462 {
1463 const bool selected_l = selected &&
1465 const bool selected_r = selected &&
1467 const bool show_l = show_handles || selected_l;
1468 const bool show_r = show_handles || selected_r;
1469 if (show_l) {
1470 data.flags |= GPU_SEQ_FLAG_DRAW_LH;
1471 }
1472 if (show_r) {
1473 data.flags |= GPU_SEQ_FLAG_DRAW_RH;
1474 }
1475 if (selected_l) {
1476 data.flags |= GPU_SEQ_FLAG_SELECTED_LH;
1477 }
1478 if (selected_r) {
1479 data.flags |= GPU_SEQ_FLAG_SELECTED_RH;
1480 }
1481 }
1482}
1483
1485 StripsDrawBatch &strips_batch,
1486 const Vector<StripDrawContext> &strips)
1487{
1489 wmOrtho2_region_pixelspace(timeline_ctx->region);
1491
1492 for (const StripDrawContext &strip : strips) {
1493 SeqStripDrawData &data = strips_batch.add_strip(strip.content_start,
1494 strip.content_end,
1495 strip.top,
1496 strip.bottom,
1497 strip.strip_content_top,
1498 strip.left_handle,
1499 strip.right_handle,
1500 strip.handle_width,
1501 strip.is_single_image);
1502 data.flags |= GPU_SEQ_FLAG_BORDER;
1504 strip_data_lock_flags_set(strip, timeline_ctx, data);
1505 strip_data_outline_params_set(strip, timeline_ctx, data);
1506 strip_data_highlight_flags_set(strip, timeline_ctx, data);
1507 strip_data_handle_flags_set(strip, timeline_ctx, data);
1508 }
1509
1510 strips_batch.flush_batch();
1513}
1514
1516 const Vector<StripDrawContext> &strips)
1517{
1519 wmOrtho2_region_pixelspace(timeline_ctx->region);
1520
1521 for (const StripDrawContext &strip_ctx : strips) {
1522 sequencer_retiming_draw_continuity(timeline_ctx, strip_ctx);
1523 }
1524 timeline_ctx->quads->draw();
1525
1527}
1528
1529static void draw_seq_strips(TimelineDrawContext *timeline_ctx,
1530 StripsDrawBatch &strips_batch,
1531 const Vector<StripDrawContext> &strips)
1532{
1533 if (strips.is_empty()) {
1534 return;
1535 }
1536
1537 UI_view2d_view_ortho(timeline_ctx->v2d);
1538
1539 /* Draw parts of strips below thumbnails. */
1540 draw_strips_background(timeline_ctx, strips_batch, strips);
1541
1543 const float round_radius = calc_strip_round_radius(timeline_ctx->pixely);
1544 for (const StripDrawContext &strip_ctx : strips) {
1545 draw_strip_offsets(timeline_ctx, &strip_ctx);
1546 drawmeta_contents(timeline_ctx, &strip_ctx, round_radius);
1547 }
1548 timeline_ctx->quads->draw();
1549
1550 /* Draw thumbnails. */
1551 draw_strip_thumbnails(timeline_ctx, strips_batch, strips);
1552 /* Draw retiming continuity ranges. */
1553 draw_retiming_continuity_ranges(timeline_ctx, strips);
1554
1555 /* Draw parts of strips above thumbnails. */
1557 for (const StripDrawContext &strip_ctx : strips) {
1558 draw_seq_fcurve_overlay(timeline_ctx, &strip_ctx);
1559 draw_seq_waveform_overlay(timeline_ctx, &strip_ctx);
1560 draw_multicam_highlight(timeline_ctx, &strip_ctx);
1561 draw_handle_transform_text(timeline_ctx, &strip_ctx, SEQ_HANDLE_LEFT);
1562 draw_handle_transform_text(timeline_ctx, &strip_ctx, SEQ_HANDLE_RIGHT);
1563 draw_seq_text_overlay(timeline_ctx, &strip_ctx);
1564 sequencer_retiming_speed_draw(timeline_ctx, strip_ctx);
1565 }
1566 sequencer_retiming_keys_draw(timeline_ctx, strips);
1567 timeline_ctx->quads->draw();
1568
1569 draw_strips_foreground(timeline_ctx, strips_batch, strips);
1570
1571 /* Draw icons. */
1572 draw_strip_icons(timeline_ctx, strips);
1573
1574 /* Draw text labels. */
1575 UI_view2d_text_cache_draw(timeline_ctx->region);
1577}
1578
1579static void draw_seq_strips(TimelineDrawContext *timeline_ctx, StripsDrawBatch &strips_batch)
1580{
1581 if (timeline_ctx->ed == nullptr) {
1582 return;
1583 }
1584
1585 /* Discard thumbnail requests that are far enough from viewing area:
1586 * by +- 30 frames and +-2 channels outside of current view. */
1587 rctf rect = timeline_ctx->v2d->cur;
1588 rect.xmin -= 30;
1589 rect.xmax += 30;
1590 rect.ymin -= 2;
1591 rect.ymax += 2;
1594
1595 Vector<StripDrawContext> bottom_layer, top_layer;
1596 visible_strips_ordered_get(timeline_ctx, bottom_layer, top_layer);
1597 draw_seq_strips(timeline_ctx, strips_batch, bottom_layer);
1598 draw_seq_strips(timeline_ctx, strips_batch, top_layer);
1599}
1600
1602{
1603 const Scene *scene = ctx->scene;
1604 const View2D *v2d = ctx->v2d;
1605 const Editing *ed = SEQ_editing_get(scene);
1606 const int frame_sta = scene->r.sfra;
1607 const int frame_end = scene->r.efra + 1;
1608
1610
1613
1614 /* Draw overlay outside of frame range. */
1616
1617 if (frame_sta < frame_end) {
1618 immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, float(frame_sta), v2d->cur.ymax);
1619 immRectf(pos, float(frame_end), v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
1620 }
1621 else {
1622 immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
1623 }
1624
1626
1627 /* Draw frame range boundary. */
1629
1630 immVertex2f(pos, frame_sta, v2d->cur.ymin);
1631 immVertex2f(pos, frame_sta, v2d->cur.ymax);
1632
1633 immVertex2f(pos, frame_end, v2d->cur.ymin);
1634 immVertex2f(pos, frame_end, v2d->cur.ymax);
1635
1636 immEnd();
1637
1638 /* While in meta strip, draw a checkerboard overlay outside of frame range. */
1639 if (ed && !BLI_listbase_is_empty(&ed->metastack)) {
1640 const MetaStack *ms = static_cast<const MetaStack *>(ed->metastack.last);
1642
1644
1645 immUniform4f("color1", 0.0f, 0.0f, 0.0f, 0.22f);
1646 immUniform4f("color2", 1.0f, 1.0f, 1.0f, 0.0f);
1647 immUniform1i("size", 8);
1648
1649 immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, ms->disp_range[0], v2d->cur.ymax);
1650 immRectf(pos, ms->disp_range[1], v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
1651
1653
1656
1658
1659 immVertex2f(pos, ms->disp_range[0], v2d->cur.ymin);
1660 immVertex2f(pos, ms->disp_range[0], v2d->cur.ymax);
1661
1662 immVertex2f(pos, ms->disp_range[1], v2d->cur.ymin);
1663 immVertex2f(pos, ms->disp_range[1], v2d->cur.ymax);
1664
1665 immEnd();
1666 }
1667
1669
1671}
1672
1680
1681/* Called as a callback. */
1682static bool draw_cache_view_init_fn(void * /*userdata*/, size_t item_count)
1683{
1684 return item_count == 0;
1685}
1686
1687/* Called as a callback */
1688static bool draw_cache_view_iter_fn(void *userdata,
1689 Sequence *seq,
1690 int timeline_frame,
1691 int cache_type)
1692{
1693 CacheDrawData *drawdata = static_cast<CacheDrawData *>(userdata);
1694 const View2D *v2d = drawdata->v2d;
1695 float stripe_top, stripe_bot;
1696
1697 /* NOTE: Final color is the same as the movie clip cache color.
1698 * See ED_region_cache_draw_cached_segments.
1699 */
1700 const uchar4 col_final{108, 108, 210, 255};
1701 const uchar4 col_raw{255, 25, 5, 100};
1702 const uchar4 col_preproc{25, 25, 191, 100};
1703 const uchar4 col_composite{255, 153, 0, 100};
1704
1705 uchar4 col{0, 0, 0, 0};
1706
1707 bool dev_ui = (U.flag & USER_DEVELOPER_UI);
1708
1709 if ((cache_type & SEQ_CACHE_STORE_FINAL_OUT) &&
1711 {
1712 /* Draw the final cache on top of the timeline */
1713 stripe_top = v2d->cur.ymax - (UI_TIME_SCRUB_MARGIN_Y / UI_view2d_scale_get_y(v2d));
1714 stripe_bot = stripe_top - (UI_TIME_CACHE_MARGIN_Y / UI_view2d_scale_get_y(v2d));
1715 col = col_final;
1716 }
1717 else {
1718 if (!dev_ui) {
1719 /* Don't show these cache types below unless developer extras is on. */
1720 return false;
1721 }
1722 if ((cache_type & SEQ_CACHE_STORE_RAW) && (drawdata->cache_flag & SEQ_CACHE_SHOW_RAW)) {
1723 stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + drawdata->stripe_ofs_y;
1724 col = col_raw;
1725 }
1726 else if ((cache_type & SEQ_CACHE_STORE_PREPROCESSED) &&
1728 {
1729 stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + drawdata->stripe_ht +
1730 drawdata->stripe_ofs_y * 2;
1731 col = col_preproc;
1732 }
1733 else if ((cache_type & SEQ_CACHE_STORE_COMPOSITE) &&
1735 {
1736 stripe_bot = seq->machine + SEQ_STRIP_OFSTOP - drawdata->stripe_ofs_y - drawdata->stripe_ht;
1737 col = col_composite;
1738 }
1739 else {
1740 return false;
1741 }
1742 stripe_top = stripe_bot + drawdata->stripe_ht;
1743 }
1744
1745 drawdata->quads->add_quad(timeline_frame, stripe_bot, timeline_frame + 1, stripe_top, col);
1746
1747 return false;
1748}
1749
1750static void draw_cache_stripe(const Scene *scene,
1751 const Sequence *seq,
1752 SeqQuadsBatch &quads,
1753 const float stripe_bot,
1754 const float stripe_ht,
1755 const uchar color[4])
1756{
1757 quads.add_quad(SEQ_time_left_handle_frame_get(scene, seq),
1758 stripe_bot,
1760 stripe_bot + stripe_ht,
1761 color);
1762}
1763
1764static void draw_cache_background(const bContext *C, CacheDrawData *draw_data)
1765{
1766 const Scene *scene = CTX_data_scene(C);
1767 const View2D *v2d = UI_view2d_fromcontext(C);
1768 const SpaceSeq *sseq = CTX_wm_space_seq(C);
1769
1770 /* NOTE: Final bg color is the same as the movie clip cache color.
1771 * See ED_region_cache_draw_background.
1772 */
1773 const uchar4 bg_final{78, 78, 145, 255};
1774 const uchar4 bg_raw{255, 25, 5, 25};
1775 const uchar4 bg_preproc{25, 25, 191, 25};
1776 const uchar4 bg_composite{255, 153, 0, 25};
1777
1778 float stripe_bot;
1779 bool dev_ui = (U.flag & USER_DEVELOPER_UI);
1780
1782 /* Draw the final cache on top of the timeline */
1783 float stripe_top = v2d->cur.ymax - (UI_TIME_SCRUB_MARGIN_Y / UI_view2d_scale_get_y(v2d));
1784 stripe_bot = stripe_top - (UI_TIME_CACHE_MARGIN_Y / UI_view2d_scale_get_y(v2d));
1785
1786 draw_data->quads->add_quad(scene->r.sfra, stripe_bot, scene->r.efra, stripe_top, bg_final);
1787 }
1788
1789 if (!dev_ui) {
1790 /* Don't show these cache types below unless developer extras is on. */
1791 return;
1792 }
1793
1795 strips.remove_if([&](Sequence *seq) { return seq->type == SEQ_TYPE_SOUND_RAM; });
1796
1797 for (const Sequence *seq : strips) {
1798 stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + draw_data->stripe_ofs_y;
1800 draw_cache_stripe(scene, seq, *draw_data->quads, stripe_bot, draw_data->stripe_ht, bg_raw);
1801 }
1802
1804 stripe_bot += draw_data->stripe_ht + draw_data->stripe_ofs_y;
1806 scene, seq, *draw_data->quads, stripe_bot, draw_data->stripe_ht, bg_preproc);
1807 }
1808
1810 stripe_bot = seq->machine + SEQ_STRIP_OFSTOP - draw_data->stripe_ofs_y -
1811 draw_data->stripe_ht;
1813 scene, seq, *draw_data->quads, stripe_bot, draw_data->stripe_ht, bg_composite);
1814 }
1815 }
1816}
1817
1818static void draw_cache_view(const bContext *C)
1819{
1820 Scene *scene = CTX_data_scene(C);
1821 const View2D *v2d = UI_view2d_fromcontext(C);
1822 const SpaceSeq *sseq = CTX_wm_space_seq(C);
1823
1824 if ((sseq->flag & SEQ_SHOW_OVERLAY) == 0 || (sseq->cache_overlay.flag & SEQ_CACHE_SHOW) == 0) {
1825 return;
1826 }
1827
1828 float stripe_ofs_y = UI_view2d_region_to_view_y(v2d, 1.0f) - v2d->cur.ymin;
1829 float stripe_ht = UI_view2d_region_to_view_y(v2d, 4.0f * UI_SCALE_FAC * U.pixelsize) -
1830 v2d->cur.ymin;
1831
1832 CLAMP_MAX(stripe_ht, 0.2f);
1833 CLAMP_MIN(stripe_ofs_y, stripe_ht / 2);
1834
1835 SeqQuadsBatch quads;
1836 CacheDrawData userdata;
1837 userdata.v2d = v2d;
1838 userdata.stripe_ofs_y = stripe_ofs_y;
1839 userdata.stripe_ht = stripe_ht;
1840 userdata.cache_flag = sseq->cache_overlay.flag;
1841 userdata.quads = &quads;
1842
1844
1845 draw_cache_background(C, &userdata);
1847
1848 quads.draw();
1850}
1851
1852/* Draw sequencer timeline. */
1853static void draw_overlap_frame_indicator(const Scene *scene, const View2D *v2d)
1854{
1855 int overlap_frame = (scene->ed->overlay_frame_flag & SEQ_EDIT_OVERLAY_FRAME_ABS) ?
1856 scene->ed->overlay_frame_abs :
1857 scene->r.cfra + scene->ed->overlay_frame_ofs;
1858
1861 float viewport_size[4];
1862 GPU_viewport_size_get_f(viewport_size);
1863 immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
1864 /* Shader may have color set from past usage - reset it. */
1865 immUniform1i("colors_len", 0);
1866 immUniform1f("dash_width", 20.0f * U.pixelsize);
1867 immUniform1f("udash_factor", 0.5f);
1869
1871 immVertex2f(pos, overlap_frame, v2d->cur.ymin);
1872 immVertex2f(pos, overlap_frame, v2d->cur.ymax);
1873 immEnd();
1874
1876}
1877
1879{
1880 if ((ctx->sseq->flag & SEQ_SHOW_OVERLAY) == 0 ||
1882 {
1883 return;
1884 }
1885
1886 U.v2d_min_gridsize *= 3;
1888 ctx->v2d, ctx->scene, (ctx->sseq->flag & SEQ_DRAWFRAMES) == 0, false);
1889 U.v2d_min_gridsize /= 3;
1890}
1891
1893{
1894 if (ctx->sseq->view != SEQ_VIEW_SEQUENCE || (ctx->sseq->draw_flag & SEQ_DRAW_BACKDROP) == 0) {
1895 return;
1896 }
1897
1898 int preview_frame = ctx->scene->r.cfra;
1901 }
1902
1904 ctx->C, ctx->scene, ctx->region, ctx->sseq, preview_frame, 0, false, true);
1906}
1907
1909{
1910 if ((ctx->sseq->flag & SEQ_SHOW_MARKERS) == 0) {
1911 return;
1912 }
1913
1914 UI_view2d_view_orthoSpecial(ctx->region, ctx->v2d, true);
1916}
1917
1919{
1920 if ((ctx->sseq->gizmo_flag & SEQ_GIZMO_HIDE) != 0) {
1921 return;
1922 }
1923
1925}
1926
1935
1942
1943void draw_timeline_seq(const bContext *C, ARegion *region)
1944{
1945 SeqQuadsBatch quads_batch;
1946 TimelineDrawContext ctx = timeline_draw_context_get(C, &quads_batch);
1947 StripsDrawBatch strips_batch(ctx.v2d);
1948
1952 draw_timeline_grid(&ctx);
1955 draw_seq_strips(&ctx, strips_batch);
1958 ANIM_draw_previewrange(C, ctx.v2d, 1);
1961 ED_time_scrub_draw(region, ctx.scene, !(ctx.sseq->flag & SEQ_DRAWFRAMES), true);
1962
1964}
1965
1967{
1968 const Scene *scene = CTX_data_scene(C);
1969 const SpaceSeq *sseq = CTX_wm_space_seq(C);
1970 View2D *v2d = &region->v2d;
1971
1972 if (scene->ed != nullptr) {
1974 draw_cache_view(C);
1975 if (scene->ed->overlay_frame_flag & SEQ_EDIT_OVERLAY_FRAME_SHOW) {
1976 draw_overlap_frame_indicator(scene, v2d);
1977 }
1979 }
1980
1981 ED_time_scrub_draw_current_frame(region, scene, !(sseq->flag & SEQ_DRAWFRAMES));
1982
1983 if (region->winy > HEADERY * UI_SCALE_FAC) {
1984 const ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
1985 SEQ_timeline_boundbox(scene, seqbase, &v2d->tot);
1986 const rcti scroller_mask = ED_time_scrub_clamp_scroller_mask(v2d->mask);
1987 UI_view2d_scrollers_draw(v2d, &scroller_mask);
1988 }
1989}
Scene * CTX_data_scene(const bContext *C)
SpaceSeq * CTX_wm_space_seq(const bContext *C)
ARegion * CTX_wm_region(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:14
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:791
#define BLI_assert(a)
Definition BLI_assert.h:50
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
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)
void rgb_byte_set_hue_float_offset(unsigned char rgb[3], float hue_offset)
void rgb_float_to_uchar(unsigned char r_col[3], const float col_f[3])
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:193
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:189
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:197
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition BLI_rect.h:201
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
#define SNPRINTF_RLEN(dst, format,...)
Definition BLI_string.h:598
char * BLI_strncpy(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)
eSeqOverlapMode
@ SEQ_OVERLAP_OVERWRITE
#define FPS
#define HEADERY
@ RGN_TYPE_WINDOW
@ SEQ_CACHE_STORE_PREPROCESSED
@ SEQ_CACHE_STORE_RAW
@ SEQ_CACHE_STORE_FINAL_OUT
@ SEQ_CACHE_STORE_COMPOSITE
@ SEQ_TYPE_TRANSFORM
@ SEQ_TYPE_SOUND_RAM
@ SEQ_TYPE_CROSS
@ SEQ_TYPE_GLOW
@ SEQ_TYPE_COLORMIX
@ SEQ_TYPE_WIPE
@ SEQ_TYPE_META
@ SEQ_TYPE_OVERDROP
@ SEQ_TYPE_ALPHAUNDER
@ SEQ_TYPE_SCENE
@ SEQ_TYPE_GAMCROSS
@ SEQ_TYPE_MULTICAM
@ SEQ_TYPE_MOVIECLIP
@ SEQ_TYPE_MUL
@ SEQ_TYPE_GAUSSIAN_BLUR
@ SEQ_TYPE_ADD
@ SEQ_TYPE_ALPHAOVER
@ SEQ_TYPE_TEXT
@ SEQ_TYPE_IMAGE
@ SEQ_TYPE_SUB
@ SEQ_TYPE_SPEED
@ SEQ_TYPE_COLOR
@ SEQ_TYPE_MOVIE
@ SEQ_TYPE_MASK
@ SEQ_TYPE_ADJUSTMENT
@ SEQUENCE_COLOR_NONE
@ SEQUENCE_COLOR_TOT
@ SEQ_SCENE_STRIPS
@ SEQ_OVERLAP
@ SEQ_AUDIO_DRAW_WAVEFORM
#define SEQ_STRIP_OFSBOTTOM
@ SEQ_EDIT_OVERLAY_FRAME_ABS
@ SEQ_EDIT_OVERLAY_FRAME_SHOW
#define SEQ_STRIP_OFSTOP
@ 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_VIEW_SEQUENCE
@ SEQ_DRAW_BACKDROP
@ SEQ_CACHE_SHOW_PREPROCESSED
@ SEQ_CACHE_SHOW_RAW
@ SEQ_CACHE_SHOW_COMPOSITE
@ SEQ_CACHE_SHOW
@ SEQ_CACHE_SHOW_FINAL_OUT
@ SEQ_DRAWFRAMES
@ SEQ_SHOW_MARKERS
@ SEQ_SHOW_OVERLAY
@ SEQ_GIZMO_HIDE
@ USER_DEVELOPER_UI
#define UI_SCALE_FAC
#define UI_INV_SCALE_FAC
@ USER_SEQ_ED_SIMPLE_TWEAKING
@ DRAW_MARKERS_MARGIN
Definition ED_markers.hh:25
Sequence * ED_sequencer_special_preview_get()
bool ED_sequencer_can_select_handle(const Scene *scene, const Sequence *seq, const View2D *v2d)
bool ED_sequencer_handle_is_selected(const Sequence *seq, eSeqHandle handle)
eSeqHandle
@ SEQ_HANDLE_LEFT
@ SEQ_HANDLE_RIGHT
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(GPUFrameBuffer *framebuffer)
void GPU_framebuffer_bind(GPUFrameBuffer *framebuffer)
void immUniform4f(const char *name, float x, float y, float z, float w)
void immEnd()
void immUnbindProgram()
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 immBindBuiltinProgram(eGPUBuiltinShader shader_id)
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_DRAW_RH
@ GPU_SEQ_FLAG_SELECTED_LH
@ GPU_SEQ_FLAG_SELECTED_RH
@ GPU_SEQ_FLAG_OVERLAP
@ GPU_SEQ_FLAG_ACTIVE
@ GPU_SEQ_FLAG_MISSING_TITLE
@ GPU_SEQ_FLAG_DRAW_LH
@ 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(eGPUBlend blend)
Definition gpu_state.cc:42
@ GPU_DEPTH_NONE
Definition GPU_state.hh:108
void GPU_depth_test(eGPUDepthTest test)
Definition gpu_state.cc:68
void GPU_viewport_size_get_f(float coords[4])
Definition gpu_state.cc:262
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
GPUFrameBuffer * GPU_viewport_framebuffer_overlay_get(GPUViewport *viewport)
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
constexpr int SEQ_MAX_CHANNELS
#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])
void UI_view2d_view_orthoSpecial(ARegion *region, View2D *v2d, bool xaxis)
Definition view2d.cc:1132
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:2077
void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
Definition view2d.cc:1605
#define UI_TIME_CACHE_MARGIN_Y
Definition UI_view2d.hh:473
void UI_view2d_view_restore(const bContext *C)
Definition view2d.cc:1158
void UI_view2d_text_cache_draw(ARegion *region)
Definition view2d.cc:2137
float UI_view2d_region_to_view_y(const View2D *v2d, float y)
Definition view2d.cc:1657
#define UI_TIME_SCRUB_MARGIN_Y
Definition UI_view2d.hh:472
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:2107
void UI_view2d_view_ortho(const View2D *v2d)
Definition view2d.cc:1091
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:1850
float UI_view2d_scale_get_y(const View2D *v2d)
Definition view2d.cc:1920
@ WM_GIZMOMAP_DRAWSTEP_2D
#define ND_SEQUENCER
Definition WM_types.hh:404
#define NC_SCENE
Definition WM_types.hh:345
void ANIM_draw_previewrange(const bContext *C, View2D *v2d, int end_frame_width)
Definition anim_draw.cc:73
void ED_markers_draw(const bContext *C, int flag)
float evaltime
unsigned int U
Definition btGjkEpa3.h:78
ListBase * SEQ_channels_displayed_get(Editing *ed)
Definition channels.cc:23
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])
void add_quad(float x1, float y1, float x2, float y2, const uchar color[4])
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)
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 col
uint top
void SEQ_cache_iterate(Scene *scene, void *userdata, bool callback_init(void *userdata, size_t item_count), bool callback_iter(void *userdata, Sequence *seq, int timeline_frame, int cache_type))
ccl_device_inline float2 floor(const float2 a)
#define G(x, y, z)
uint color_pack(const uchar rgba[4])
float calc_strip_round_radius(float pixely)
void thumbnail_cache_discard_requests_outside(Scene *scene, const rctf &rect)
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:95
bool SEQ_prefetch_need_redraw(const bContext *C, Scene *scene)
Definition prefetch.cc:583
bool SEQ_render_is_muted(const ListBase *channels, const Sequence *seq)
Definition render.cc:2154
const char * SEQ_sequence_give_name(const Sequence *seq)
ListBase * SEQ_get_seqbase_from_sequence(Sequence *seq, ListBase **r_channels, int *r_offset)
bool SEQ_sequence_has_valid_data(const Sequence *seq)
ListBase * SEQ_active_seqbase_get(const Editing *ed)
Definition sequencer.cc:416
eSeqOverlapMode SEQ_tool_settings_overlap_mode_get(Scene *scene)
Definition sequencer.cc:404
Editing * SEQ_editing_get(const Scene *scene)
Definition sequencer.cc:262
void sequencer_retiming_draw_continuity(const TimelineDrawContext *timeline_ctx, const StripDrawContext &strip_ctx)
void sequencer_draw_preview(const bContext *C, Scene *scene, ARegion *region, SpaceSeq *sseq, int timeline_frame, int offset, bool draw_overlay, bool draw_backdrop)
bool sequencer_draw_get_transform_preview(SpaceSeq *sseq, Scene *scene)
void sequencer_retiming_keys_draw(const TimelineDrawContext *timeline_ctx, blender::Span< StripDrawContext > strips)
void draw_strip_thumbnails(TimelineDrawContext *ctx, blender::ed::seq::StripsDrawBatch &strips_batch, const blender::Vector< StripDrawContext > &strips)
void sequencer_retiming_speed_draw(const TimelineDrawContext *timeline_ctx, const StripDrawContext &strip_ctx)
bool retiming_keys_can_be_displayed(const SpaceSeq *sseq)
void sequencer_preview_add_sound(const bContext *C, const Sequence *seq)
int sequencer_draw_get_transform_preview_frame(Scene *scene)
static void draw_timeline_backdrop(TimelineDrawContext *ctx)
static void seq_prefetch_wm_notify(const bContext *C, Scene *scene)
static void draw_cache_view(const bContext *C)
static void draw_seq_waveform_overlay(TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx)
static float align_frame_with_pixel(float frame_coord, float frames_per_pixel)
Vector< Sequence * > sequencer_visible_strips_get(const bContext *C)
static void strip_data_handle_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_timeline_markers(TimelineDrawContext *ctx)
static void draw_strips_background(TimelineDrawContext *timeline_ctx, StripsDrawBatch &strips_batch, const Vector< StripDrawContext > &strips)
static void draw_strip_offsets(TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx)
static void draw_cache_stripe(const Scene *scene, const Sequence *seq, SeqQuadsBatch &quads, const float stripe_bot, const float stripe_ht, const uchar color[4])
void draw_timeline_seq_display(const bContext *C, ARegion *region)
static void strip_data_missing_media_flags_set(const StripDrawContext &strip, SeqStripDrawData &data)
static void draw_icon_centered(TimelineDrawContext &ctx, const rctf &rect, int icon_id, const uchar color[4])
static void draw_timeline_gizmos(TimelineDrawContext *ctx)
static void visible_strips_ordered_get(TimelineDrawContext *timeline_ctx, Vector< StripDrawContext > &r_bottom_layer, Vector< StripDrawContext > &r_top_layer)
static void color3ubv_from_seq(const Scene *curscene, const Sequence *seq, const bool show_strip_color_tag, const bool is_muted, uchar r_col[3])
static void draw_seq_strips(TimelineDrawContext *timeline_ctx, StripsDrawBatch &strips_batch, const Vector< StripDrawContext > &strips)
static StripDrawContext strip_draw_context_get(TimelineDrawContext *ctx, Sequence *seq)
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_seq_text_get_source(const Sequence *seq, char *r_source, size_t source_maxncpy)
static const char * draw_seq_text_get_name(const Sequence *seq)
static void draw_multicam_highlight(TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx)
static void waveform_job_start_if_needed(const bContext *C, const Sequence *seq)
static bool draw_cache_view_init_fn(void *, size_t item_count)
static void draw_seq_fcurve_overlay(TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx)
static void draw_timeline_grid(TimelineDrawContext *ctx)
static void draw_seq_text_overlay(TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx)
static void draw_seq_timeline_channels(TimelineDrawContext *ctx)
static bool draw_cache_view_iter_fn(void *userdata, Sequence *seq, int timeline_frame, int cache_type)
static void draw_strip_icons(TimelineDrawContext *timeline_ctx, const Vector< StripDrawContext > &strips)
static void strip_data_highlight_flags_set(const StripDrawContext &strip, const TimelineDrawContext *timeline_ctx, SeqStripDrawData &data)
static bool strip_hides_text_overlay_first(const TimelineDrawContext *ctx, const StripDrawContext *strip_ctx)
constexpr float ICON_SIZE
void draw_timeline_seq(const bContext *C, ARegion *region)
static void draw_timeline_sfra_efra(TimelineDrawContext *ctx)
static void draw_overlap_frame_indicator(const Scene *scene, const View2D *v2d)
static bool seq_draw_waveforms_poll(const SpaceSeq *sseq, const Sequence *seq)
static void drawmeta_contents(TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx, float corner_radius)
static void get_strip_text_color(const StripDrawContext *strip, uchar r_col[4])
static void strip_draw_context_curve_get(const TimelineDrawContext *ctx, StripDrawContext &strip_ctx)
constexpr int MUTE_ALPHA
static TimelineDrawContext timeline_draw_context_get(const bContext *C, SeqQuadsBatch *quads_batch)
static void strip_draw_context_set_strip_content_visibility(TimelineDrawContext *ctx, StripDrawContext *strip_ctx)
float sequence_handle_size_get_clamped(const Scene *scene, Sequence *seq, const float pixelx)
static void strip_data_lock_flags_set(const StripDrawContext &strip, const TimelineDrawContext *timeline_ctx, SeqStripDrawData &data)
static void draw_cache_background(const bContext *C, CacheDrawData *draw_data)
static void strip_draw_context_set_text_overlay_visibility(TimelineDrawContext *ctx, StripDrawContext *strip_ctx)
static void draw_timeline_pre_view_callbacks(TimelineDrawContext *ctx)
static void draw_timeline_post_view_callbacks(TimelineDrawContext *ctx)
static void draw_strips_foreground(TimelineDrawContext *timeline_ctx, StripsDrawBatch &strips_batch, const Vector< StripDrawContext > &strips)
static void draw_retiming_continuity_ranges(TimelineDrawContext *timeline_ctx, const Vector< StripDrawContext > &strips)
static void draw_handle_transform_text(const TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx, eSeqHandle handle)
static void strip_data_outline_params_set(const StripDrawContext &strip, const TimelineDrawContext *timeline_ctx, SeqStripDrawData &data)
bool SEQ_is_strip_connected(const Sequence *seq)
blender::Map< SeqRetimingKey *, Sequence * > SEQ_retiming_selection_get(const Editing *ed)
Sequence * SEQ_select_active_get(const Scene *scene)
float SEQ_give_frame_index(const Scene *scene, const Sequence *seq, float timeline_frame)
Definition strip_time.cc:60
int SEQ_time_left_handle_frame_get(const Scene *, const Sequence *seq)
float SEQ_time_content_end_frame_get(const Scene *scene, const Sequence *seq)
void SEQ_timeline_boundbox(const Scene *scene, const ListBase *seqbase, rctf *r_rect)
float SEQ_time_start_frame_get(const Sequence *seq)
int SEQ_time_right_handle_frame_get(const Scene *scene, const Sequence *seq)
bool SEQ_transform_is_locked(ListBase *channels, const Sequence *seq)
bool SEQ_transform_single_image_check(const Sequence *seq)
struct wmGizmoMap * gizmo_map
ListBase * seqbasep
ListBase metastack
char name[66]
Definition DNA_ID.h:425
void * last
struct RenderData r
struct MovieClip * clip
struct Scene * scene
struct Object * scene_camera
struct Mask * mask
struct bSound * sound
struct Sequence * seq1
struct Sequence * seq2
float * data
Definition BKE_sound.h:28
struct SequencerCacheOverlay cache_overlay
struct SequencerTimelineOverlay timeline_overlay
const FCurve * curve
char filename[256]
char dirpath[768]
StripElem * stripdata
unsigned char color[4]
blender::Map< SeqRetimingKey *, Sequence * > retiming_selection
GPUFrameBuffer * framebuffer_overlay
char filepath[1024]
void * spinlock
void * waveform
double offset_time
ThemeStripColor strip_color[9]
float xmax
float xmin
float ymax
float ymin
rcti ED_time_scrub_clamp_scroller_mask(const rcti &scroller_mask)
void ED_time_scrub_draw_current_frame(const ARegion *region, const Scene *scene, bool display_seconds)
void ED_time_scrub_draw(const ARegion *region, const Scene *scene, bool display_seconds, bool discrete_frames)
GPUViewport * WM_draw_region_get_viewport(ARegion *region)
Definition wm_draw.cc:905
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)