Blender V4.5
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_vector.h"
15#include "BLI_path_utils.hh"
16#include "BLI_string.h"
17#include "BLI_string_utils.hh"
18#include "BLI_task.hh"
19#include "BLI_threads.h"
20#include "BLI_utildefines.h"
21
22#include "DNA_scene_types.h"
23#include "DNA_screen_types.h"
24#include "DNA_sound_types.h"
25#include "DNA_space_types.h"
26#include "DNA_userdef_types.h"
27
28#include "BKE_context.hh"
29#include "BKE_fcurve.hh"
30#include "BKE_global.hh"
31#include "BKE_screen.hh"
32#include "BKE_sound.h"
33
34#include "ED_anim_api.hh"
35#include "ED_markers.hh"
36#include "ED_mask.hh"
37#include "ED_sequencer.hh"
38#include "ED_space_api.hh"
39#include "ED_time_scrub_ui.hh"
40
41#include "GPU_immediate.hh"
42#include "GPU_matrix.hh"
43#include "GPU_state.hh"
44
45#include "RNA_prototypes.hh"
46
47#include "SEQ_channels.hh"
48#include "SEQ_connect.hh"
49#include "SEQ_effects.hh"
50#include "SEQ_prefetch.hh"
51#include "SEQ_relations.hh"
52#include "SEQ_render.hh"
53#include "SEQ_retiming.hh"
54#include "SEQ_select.hh"
55#include "SEQ_sequencer.hh"
57#include "SEQ_time.hh"
58#include "SEQ_transform.hh"
59#include "SEQ_utils.hh"
60
61#include "UI_interface_icons.hh"
62#include "UI_resources.hh"
63#include "UI_view2d.hh"
64
65#include "WM_api.hh"
66#include "WM_types.hh"
67
68#include "BLF_api.hh"
69
70/* Own include. */
71#include "sequencer_intern.hh"
74
75namespace blender::ed::vse {
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<Strip *> strips;
90
91 LISTBASE_FOREACH (Strip *, strip, ed->seqbasep) {
93 v2d->cur.xmax)
94 {
95 continue;
96 }
98 seq::time_content_end_frame_get(scene, strip)) < v2d->cur.xmin)
99 {
100 continue;
101 }
102 if (strip->channel + 1.0f < v2d->cur.ymin) {
103 continue;
104 }
105 if (strip->channel > v2d->cur.ymax) {
106 continue;
107 }
108 strips.append(strip);
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);
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 Strip *strip)
140{
141 const bool strip_is_valid = strip->type == STRIP_TYPE_SOUND_RAM && strip->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 ||
144 (strip->flag & SEQ_AUDIO_DRAW_WAVEFORM));
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->strip) ||
161 strip_ctx->strip->type == STRIP_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 return min_ff(0.40f, 20 * UI_SCALE_FAC * ctx->pixely);
206}
207
209{
210 using namespace seq;
211 StripDrawContext strip_ctx;
212 Scene *scene = ctx->scene;
213
214 strip_ctx.strip = strip;
215 strip_ctx.bottom = strip->channel + STRIP_OFSBOTTOM;
216 strip_ctx.top = strip->channel + STRIP_OFSTOP;
217 strip_ctx.left_handle = seq::time_left_handle_frame_get(scene, strip);
218 strip_ctx.right_handle = seq::time_right_handle_frame_get(scene, strip);
219 strip_ctx.content_start = seq::time_start_frame_get(strip);
220 strip_ctx.content_end = seq::time_content_end_frame_get(scene, strip);
221
222 if (strip->type == STRIP_TYPE_SOUND_RAM && strip->sound != nullptr) {
223 /* Visualize sub-frame sound offsets. */
224 const double sound_offset = (strip->sound->offset_time + strip->sound_offset) * FPS;
225 strip_ctx.content_start += sound_offset;
226 strip_ctx.content_end += sound_offset;
227 }
228
229 /* Limit body to strip bounds. */
230 strip_ctx.content_start = min_ff(strip_ctx.content_start, strip_ctx.right_handle);
231 strip_ctx.content_end = max_ff(strip_ctx.content_end, strip_ctx.left_handle);
232
233 strip_ctx.strip_length = strip_ctx.right_handle - strip_ctx.left_handle;
234
238 strip_ctx.strip_is_too_small = (!strip_ctx.can_draw_text_overlay &&
239 !strip_ctx.can_draw_strip_content);
240 strip_ctx.is_active_strip = strip == seq::select_active_get(scene);
242 strip_ctx.handle_width = strip_handle_draw_size_get(ctx->scene, strip, ctx->pixelx);
245
246 /* Determine if strip (or contents of meta strip) has missing data/media. */
247 strip_ctx.missing_data_block = !strip_has_valid_data(strip);
248 strip_ctx.missing_media = media_presence_is_missing(scene, strip);
249 strip_ctx.is_connected = seq::is_strip_connected(strip);
250 if (strip->type == STRIP_TYPE_META) {
251 const ListBase *seqbase = &strip->seqbase;
252 LISTBASE_FOREACH (const Strip *, sub, seqbase) {
253 if (!strip_has_valid_data(sub)) {
254 strip_ctx.missing_data_block = true;
255 }
256 if (media_presence_is_missing(scene, sub)) {
257 strip_ctx.missing_media = true;
258 }
259 }
260 }
261
262 if (strip_ctx.can_draw_text_overlay) {
263 strip_ctx.strip_content_top = strip_ctx.top - strip_header_size_get(ctx);
264 }
265 else {
266 strip_ctx.strip_content_top = strip_ctx.top;
267 }
268
269 strip_ctx.is_muted = seq::render_is_muted(ctx->channels, strip);
270 strip_ctx.curve = nullptr;
271 return strip_ctx;
272}
273
275 StripDrawContext &strip_ctx)
276{
277 strip_ctx.curve = nullptr;
278 const bool showing_curve_overlay = strip_ctx.can_draw_strip_content &&
279 (ctx->sseq->flag & SEQ_SHOW_OVERLAY) != 0 &&
280 (ctx->sseq->timeline_overlay.flag &
282 const bool showing_waveform = (strip_ctx.strip->type == STRIP_TYPE_SOUND_RAM) &&
283 !strip_ctx.strip_is_too_small &&
284 seq_draw_waveforms_poll(ctx->sseq, strip_ctx.strip);
285 if (showing_curve_overlay || showing_waveform) {
286 const char *prop_name = strip_ctx.strip->type == STRIP_TYPE_SOUND_RAM ? "volume" :
287 "blend_alpha";
288 strip_ctx.curve = id_data_find_fcurve(
289 &ctx->scene->id, strip_ctx.strip, &RNA_Strip, prop_name, 0, nullptr);
290 if (strip_ctx.curve && BKE_fcurve_is_empty(strip_ctx.curve)) {
291 strip_ctx.curve = nullptr;
292 }
293 }
294}
295
296static void color3ubv_from_seq(const Scene *curscene,
297 const Strip *strip,
298 const bool show_strip_color_tag,
299 const bool is_muted,
300 uchar r_col[3])
301{
302 if (show_strip_color_tag && uint(strip->color_tag) < STRIP_COLOR_TOT &&
303 strip->color_tag != STRIP_COLOR_NONE)
304 {
305 bTheme *btheme = UI_GetTheme();
306 const ThemeStripColor *strip_color = &btheme->strip_color[strip->color_tag];
307 copy_v3_v3_uchar(r_col, strip_color->color);
308 return;
309 }
310
311 uchar blendcol[3];
312
313 /* Sometimes the active theme is not the sequencer theme, e.g. when an operator invokes the file
314 * browser. This makes sure we get the right color values for the theme. */
315 bThemeState theme_state;
316 UI_Theme_Store(&theme_state);
318
319 switch (strip->type) {
320 case STRIP_TYPE_IMAGE:
322 break;
323
324 case STRIP_TYPE_META:
326 break;
327
328 case STRIP_TYPE_MOVIE:
330 break;
331
334 break;
335
336 case STRIP_TYPE_MASK:
338 break;
339
340 case STRIP_TYPE_SCENE:
342
343 if (strip->scene == curscene) {
344 UI_GetColorPtrShade3ubv(r_col, 20, r_col);
345 }
346 break;
347
348 /* Transitions use input colors, fallback for when the input is a transition itself. */
349 case STRIP_TYPE_CROSS:
351 case STRIP_TYPE_WIPE:
353
354 /* Slightly offset hue to distinguish different transition types. */
355 if (strip->type == STRIP_TYPE_GAMCROSS) {
357 }
358 else if (strip->type == STRIP_TYPE_WIPE) {
360 }
361 break;
362
363 /* Effects. */
365 case STRIP_TYPE_SPEED:
366 case STRIP_TYPE_ADD:
367 case STRIP_TYPE_SUB:
368 case STRIP_TYPE_MUL:
371 case STRIP_TYPE_GLOW:
377
378 /* Slightly offset hue to distinguish different effects. */
379 if (strip->type == STRIP_TYPE_ADD) {
381 }
382 else if (strip->type == STRIP_TYPE_SUB) {
384 }
385 else if (strip->type == STRIP_TYPE_MUL) {
387 }
388 else if (strip->type == STRIP_TYPE_ALPHAOVER) {
390 }
391 else if (strip->type == STRIP_TYPE_ALPHAUNDER) {
393 }
394 else if (strip->type == STRIP_TYPE_COLORMIX) {
396 }
397 else if (strip->type == STRIP_TYPE_GAUSSIAN_BLUR) {
399 }
400 else if (strip->type == STRIP_TYPE_GLOW) {
402 }
403 else if (strip->type == STRIP_TYPE_ADJUSTMENT) {
405 }
406 else if (strip->type == STRIP_TYPE_SPEED) {
408 }
409 else if (strip->type == STRIP_TYPE_TRANSFORM) {
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 / FPS;
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 -
503 (strip->sound->offset_time + strip->sound_offset) * FPS;
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_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_RLEN(numstr, "%d", int(strip_ctx->left_handle));
764 text_x += text_margin;
765 }
766 else {
767 numstr_len = SNPRINTF_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 bool use_thin_handle = (U.sequencer_editor_flag & USER_SEQ_ED_SIMPLE_TWEAKING) != 0;
777 const float handle_size = use_thin_handle ? 5.0f : 8.0f;
778 const float maxhandle = (pixelx * handle_size) * U.pixelsize;
779
780 /* Ensure that handle is not wider, than quarter of strip. */
781 return min_ff(maxhandle,
782 (float(seq::time_right_handle_frame_get(scene, strip) -
783 seq::time_left_handle_frame_get(scene, strip)) /
784 4.0f));
785}
786
787static const char *draw_seq_text_get_name(const Strip *strip)
788{
789 const char *name = strip->name + 2;
790 if (name[0] == '\0') {
791 name = seq::strip_give_name(strip);
792 }
793 return name;
794}
795
796static void draw_seq_text_get_source(const Strip *strip, char *r_source, size_t source_maxncpy)
797{
798 *r_source = '\0';
799
800 /* Set source for the most common types. */
801 switch (strip->type) {
802 case STRIP_TYPE_IMAGE:
803 case STRIP_TYPE_MOVIE: {
805 r_source, source_maxncpy, strip->data->dirpath, strip->data->stripdata->filename);
806 break;
807 }
809 if (strip->sound != nullptr) {
810 BLI_strncpy(r_source, strip->sound->filepath, source_maxncpy);
811 }
812 break;
813 }
814 case STRIP_TYPE_MULTICAM: {
815 BLI_snprintf(r_source, source_maxncpy, "Channel: %d", strip->multicam_source);
816 break;
817 }
818 case STRIP_TYPE_TEXT: {
819 const TextVars *textdata = static_cast<TextVars *>(strip->effectdata);
820 BLI_strncpy(r_source, textdata->text, source_maxncpy);
821 break;
822 }
823 case STRIP_TYPE_SCENE: {
824 if (strip->scene != nullptr) {
825 if (strip->scene_camera != nullptr) {
826 BLI_snprintf(r_source,
827 source_maxncpy,
828 "%s (%s)",
829 strip->scene->id.name + 2,
830 strip->scene_camera->id.name + 2);
831 }
832 else {
833 BLI_strncpy(r_source, strip->scene->id.name + 2, source_maxncpy);
834 }
835 }
836 break;
837 }
839 if (strip->clip != nullptr) {
840 BLI_strncpy(r_source, strip->clip->id.name + 2, source_maxncpy);
841 }
842 break;
843 }
844 case STRIP_TYPE_MASK: {
845 if (strip->mask != nullptr) {
846 BLI_strncpy(r_source, strip->mask->id.name + 2, source_maxncpy);
847 }
848 break;
849 }
850 }
851}
852
854 const StripDrawContext *strip_ctx,
855 char *r_overlay_string,
856 size_t overlay_string_len)
857{
858 const Strip *strip = strip_ctx->strip;
859
860 const char *text_sep = " | ";
861 const char *text_array[5];
862 int i = 0;
863
865 text_array[i++] = draw_seq_text_get_name(strip);
866 }
867
868 char source[FILE_MAX];
870 draw_seq_text_get_source(strip, source, sizeof(source));
871 if (source[0] != '\0') {
872 if (i != 0) {
873 text_array[i++] = text_sep;
874 }
875 text_array[i++] = source;
876 }
877 }
878
879 char strip_duration_text[16];
881 SNPRINTF(strip_duration_text, "%d", int(strip_ctx->strip_length));
882 if (i != 0) {
883 text_array[i++] = text_sep;
884 }
885 text_array[i++] = strip_duration_text;
886 }
887
888 BLI_assert(i <= ARRAY_SIZE(text_array));
889
890 return BLI_string_join_array(r_overlay_string, overlay_string_len, text_array, i);
891}
892
893static void get_strip_text_color(const StripDrawContext *strip_ctx, uchar r_col[4])
894{
895 const Strip *strip = strip_ctx->strip;
896 const bool active_or_selected = (strip->flag & SELECT) || strip_ctx->is_active_strip;
897
898 /* Text: white when selected/active, black otherwise. */
899 r_col[0] = r_col[1] = r_col[2] = r_col[3] = 255;
900
901 /* If not active or selected, draw text black. */
902 if (!active_or_selected) {
903 r_col[0] = r_col[1] = r_col[2] = 0;
904
905 /* On muted and missing media/data-block strips: gray color, reduce opacity. */
906 if (strip_ctx->is_muted || strip_ctx->missing_data_block || strip_ctx->missing_media) {
907 r_col[0] = r_col[1] = r_col[2] = 192;
908 r_col[3] *= 0.66f;
909 }
910 }
911}
912
914 const rctf &rect,
915 int icon_id,
916 const uchar color[4])
917{
920
921 const float icon_size = ICON_SIZE * UI_SCALE_FAC;
922 if (BLI_rctf_size_x(&rect) * 1.1f < icon_size * ctx.pixelx ||
923 BLI_rctf_size_y(&rect) * 1.1f < icon_size * ctx.pixely)
924 {
926 return;
927 }
928
929 const float left = ((rect.xmin - ctx.v2d->cur.xmin) / ctx.pixelx);
930 const float right = ((rect.xmax - ctx.v2d->cur.xmin) / ctx.pixelx);
931 const float bottom = ((rect.ymin - ctx.v2d->cur.ymin) / ctx.pixely);
932 const float top = ((rect.ymax - ctx.v2d->cur.ymin) / ctx.pixely);
933 const float x_offset = (right - left - icon_size) * 0.5f;
934 const float y_offset = (top - bottom - icon_size) * 0.5f;
935
936 const float inv_scale_fac = (ICON_DEFAULT_HEIGHT / ICON_SIZE) * UI_INV_SCALE_FAC;
937
938 UI_icon_draw_ex(left + x_offset,
939 bottom + y_offset,
940 icon_id,
941 inv_scale_fac,
942 1.0f,
943 0.0f,
944 color,
945 false,
947
948 /* Restore view matrix. */
950}
951
952static void draw_strip_icons(TimelineDrawContext *timeline_ctx,
953 const Vector<StripDrawContext> &strips)
954{
955 const float icon_size_x = ICON_SIZE * timeline_ctx->pixelx * UI_SCALE_FAC;
956
957 for (const StripDrawContext &strip : strips) {
958 const bool missing_data = strip.missing_data_block;
959 const bool missing_media = strip.missing_media;
960 const bool is_connected = strip.is_connected;
961 if (!missing_data && !missing_media && !is_connected) {
962 continue;
963 }
964
965 /* Draw icon in the title bar area. */
966 if ((timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) != 0 && !strip.strip_is_too_small) {
967 uchar col[4];
968 get_strip_text_color(&strip, col);
969
970 float icon_indent = 2.0f * strip.handle_width - 4 * timeline_ctx->pixelx * UI_SCALE_FAC;
971 rctf rect;
972 rect.ymin = strip.top - strip_header_size_get(timeline_ctx);
973 rect.ymax = strip.top;
974 rect.xmin = max_ff(strip.left_handle, timeline_ctx->v2d->cur.xmin) + icon_indent;
975 if (missing_data) {
976 rect.xmax = min_ff(strip.right_handle - strip.handle_width, rect.xmin + icon_size_x);
977 draw_icon_centered(*timeline_ctx, rect, ICON_LIBRARY_DATA_BROKEN, col);
978 rect.xmin = rect.xmax;
979 }
980 if (missing_media) {
981 rect.xmax = min_ff(strip.right_handle - strip.handle_width, rect.xmin + icon_size_x);
982 draw_icon_centered(*timeline_ctx, rect, ICON_ERROR, col);
983 rect.xmin = rect.xmax;
984 }
985 if (is_connected) {
986 rect.xmax = min_ff(strip.right_handle - strip.handle_width, rect.xmin + icon_size_x);
987 draw_icon_centered(*timeline_ctx, rect, ICON_LINKED, col);
988 }
989 }
990
991 /* Draw icon in center of content. */
992 if (strip.can_draw_strip_content && strip.strip->type != STRIP_TYPE_META) {
993 rctf rect;
994 rect.xmin = strip.left_handle + strip.handle_width;
995 rect.xmax = strip.right_handle - strip.handle_width;
996 rect.ymin = strip.bottom;
997 rect.ymax = strip.strip_content_top;
998 uchar col[4] = {112, 0, 0, 255};
999 if (missing_data) {
1000 draw_icon_centered(*timeline_ctx, rect, ICON_LIBRARY_DATA_BROKEN, col);
1001 }
1002 if (missing_media) {
1003 draw_icon_centered(*timeline_ctx, rect, ICON_ERROR, col);
1004 }
1005 }
1006 }
1007}
1008
1009/* Draw info text on a sequence strip. */
1011 const StripDrawContext *strip_ctx)
1012{
1013 if ((timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) == 0) {
1014 return;
1015 }
1016 /* Draw text only if there is enough horizontal or vertical space. */
1017 if ((strip_ctx->strip_length <= 32 * timeline_ctx->pixelx * UI_SCALE_FAC) ||
1018 strip_ctx->strip_is_too_small || !strip_ctx->can_draw_text_overlay)
1019 {
1020 return;
1021 }
1022
1023 char overlay_string[FILE_MAX];
1024 size_t overlay_string_len = draw_seq_text_get_overlay_string(
1025 timeline_ctx, strip_ctx, overlay_string, sizeof(overlay_string));
1026
1027 if (overlay_string_len == 0) {
1028 return;
1029 }
1030
1031 uchar col[4];
1032 get_strip_text_color(strip_ctx, col);
1033
1034 float text_margin = 2.0f * strip_ctx->handle_width;
1035 rctf rect;
1036 rect.xmin = strip_ctx->left_handle + text_margin;
1037 rect.xmax = strip_ctx->right_handle - text_margin;
1038 rect.ymax = strip_ctx->top;
1039 /* Depending on the vertical space, draw text on top or in the center of strip. */
1040 rect.ymin = !strip_ctx->can_draw_strip_content ? strip_ctx->bottom :
1041 strip_ctx->strip_content_top;
1042 rect.xmin = max_ff(rect.xmin, timeline_ctx->v2d->cur.xmin + text_margin);
1043 int num_icons = 0;
1044 if (strip_ctx->missing_data_block) {
1045 num_icons++;
1046 }
1047 if (strip_ctx->missing_media) {
1048 num_icons++;
1049 }
1050 if (strip_ctx->is_connected) {
1051 num_icons++;
1052 }
1053 rect.xmin += num_icons * ICON_SIZE * timeline_ctx->pixelx * UI_SCALE_FAC;
1054 rect.xmin = min_ff(rect.xmin, timeline_ctx->v2d->cur.xmax);
1055
1056 CLAMP(rect.xmax, timeline_ctx->v2d->cur.xmin + text_margin, timeline_ctx->v2d->cur.xmax);
1057 if (rect.xmin >= rect.xmax) { /* No space for label left. */
1058 return;
1059 }
1060
1062 timeline_ctx->v2d, &rect, overlay_string, overlay_string_len, col);
1063}
1064
1065static void draw_strip_offsets(TimelineDrawContext *timeline_ctx,
1066 const StripDrawContext *strip_ctx)
1067{
1068 const Strip *strip = strip_ctx->strip;
1069 if ((timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) == 0) {
1070 return;
1071 }
1072 if (strip_ctx->is_single_image || timeline_ctx->pixely <= 0) {
1073 return;
1074 }
1075 if ((timeline_ctx->sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_OFFSETS) == 0 &&
1076 (strip_ctx->strip != special_preview_get()) &&
1077 (strip_ctx->strip->flag & SEQ_SHOW_OFFSETS) == 0)
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, strip, strip_ctx->show_strip_color_tag, strip_ctx->is_muted, col);
1086 if (strip->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 - 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 - 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 + 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 + 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 Strip *act_strip = seq::select_active_get(timeline_ctx->scene);
1198
1199 if (strip_ctx->strip != act_strip || act_strip == nullptr) {
1200 return;
1201 }
1202 if ((act_strip->flag & SELECT) == 0 || act_strip->type != STRIP_TYPE_MULTICAM) {
1203 return;
1204 }
1205
1206 int channel = act_strip->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<Strip *> strips = sequencer_visible_strips_get(timeline_ctx->C);
1259 r_bottom_layer.reserve(strips.size());
1260
1261 for (Strip *strip : strips) {
1262 StripDrawContext strip_ctx = strip_draw_context_get(timeline_ctx, strip);
1263 if ((strip->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.strip, 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.strip->type == STRIP_TYPE_COLOR)) {
1322 SolidColorVars *colvars = (SolidColorVars *)strip.strip->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 {
1332
1333 const Strip *input1 = strip.strip->input1;
1334 const Strip *input2 = strip.strip->input2;
1335
1336 /* Left side. */
1337 if (input1->type == STRIP_TYPE_COLOR) {
1338 rgb_float_to_uchar(col, ((const SolidColorVars *)input1->effectdata)->col);
1339 }
1340 else {
1341 color3ubv_from_seq(scene, input1, strip.show_strip_color_tag, strip.is_muted, col);
1342 }
1343 data.col_transition_in = color_pack(col);
1344
1345 /* Right side. */
1346 if (input2->type == STRIP_TYPE_COLOR) {
1347 rgb_float_to_uchar(col, ((const SolidColorVars *)input2->effectdata)->col);
1348 }
1349 else {
1350 color3ubv_from_seq(scene, input2, 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 (input1->type == input2->type) {
1354 }
1355 }
1356 data.col_transition_out = color_pack(col);
1357 }
1358 }
1359 strips_batch.flush_batch();
1362}
1363
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) {
1371 }
1372 /* Do not tint content area for meta strips; we want to display children. */
1373 if (strip.strip->type != STRIP_TYPE_META) {
1375 }
1376 }
1377}
1378
1380 const TimelineDrawContext *timeline_ctx,
1382{
1383 if (seq::transform_is_locked(timeline_ctx->channels, strip.strip)) {
1384 data.flags |= GPU_SEQ_FLAG_LOCKED;
1385 }
1386}
1387
1389 const TimelineDrawContext *timeline_ctx,
1391{
1392 const bool active = strip.is_active_strip;
1393 const bool selected = strip.strip->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.strip->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,
1438{
1439 const Strip *act_strip = seq::select_active_get(timeline_ctx->scene);
1440 const Strip *special_preview = special_preview_get();
1441 /* Highlight if strip is an input of an active strip, or if the strip is solo preview. */
1442 if (act_strip != nullptr && (act_strip->flag & SELECT) != 0) {
1443 if (act_strip->input1 == strip.strip || act_strip->input2 == strip.strip) {
1445 }
1446 }
1447 if (special_preview == strip.strip) {
1449 }
1450}
1451
1453 const TimelineDrawContext *timeline_ctx,
1455{
1456 const Scene *scene = timeline_ctx->scene;
1457 const bool selected = strip.strip->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.strip) &&
1461 can_select_handle(scene, strip.strip, timeline_ctx->v2d))
1462 {
1463 const bool selected_l = selected && handle_is_selected(strip.strip, STRIP_HANDLE_LEFT);
1464 const bool selected_r = selected && handle_is_selected(strip.strip, STRIP_HANDLE_RIGHT);
1465 const bool show_l = show_handles || selected_l;
1466 const bool show_r = show_handles || selected_r;
1467 if (show_l) {
1468 data.flags |= GPU_SEQ_FLAG_DRAW_LH;
1469 }
1470 if (show_r) {
1471 data.flags |= GPU_SEQ_FLAG_DRAW_RH;
1472 }
1473 if (selected_l) {
1475 }
1476 if (selected_r) {
1478 }
1479 }
1480}
1481
1483 StripsDrawBatch &strips_batch,
1484 const Vector<StripDrawContext> &strips)
1485{
1487 wmOrtho2_region_pixelspace(timeline_ctx->region);
1489
1490 for (const StripDrawContext &strip : strips) {
1491 SeqStripDrawData &data = strips_batch.add_strip(strip.content_start,
1492 strip.content_end,
1493 strip.top,
1494 strip.bottom,
1495 strip.strip_content_top,
1496 strip.left_handle,
1497 strip.right_handle,
1498 strip.handle_width,
1499 strip.is_single_image);
1500 data.flags |= GPU_SEQ_FLAG_BORDER;
1502 strip_data_lock_flags_set(strip, timeline_ctx, data);
1503 strip_data_outline_params_set(strip, timeline_ctx, data);
1504 strip_data_highlight_flags_set(strip, timeline_ctx, data);
1505 strip_data_handle_flags_set(strip, timeline_ctx, data);
1506 }
1507
1508 strips_batch.flush_batch();
1511}
1512
1514 const Vector<StripDrawContext> &strips)
1515{
1517 wmOrtho2_region_pixelspace(timeline_ctx->region);
1518
1519 for (const StripDrawContext &strip_ctx : strips) {
1520 sequencer_retiming_draw_continuity(timeline_ctx, strip_ctx);
1521 }
1522 timeline_ctx->quads->draw();
1523
1525}
1526
1527static void draw_seq_strips(TimelineDrawContext *timeline_ctx,
1528 StripsDrawBatch &strips_batch,
1529 const Vector<StripDrawContext> &strips)
1530{
1531 if (strips.is_empty()) {
1532 return;
1533 }
1534
1535 UI_view2d_view_ortho(timeline_ctx->v2d);
1536
1537 /* Draw parts of strips below thumbnails. */
1538 draw_strips_background(timeline_ctx, strips_batch, strips);
1539
1541 const float round_radius = calc_strip_round_radius(timeline_ctx->pixely);
1542 for (const StripDrawContext &strip_ctx : strips) {
1543 draw_strip_offsets(timeline_ctx, &strip_ctx);
1544 drawmeta_contents(timeline_ctx, &strip_ctx, round_radius);
1545 }
1546 timeline_ctx->quads->draw();
1547
1548 /* Draw thumbnails. */
1549 draw_strip_thumbnails(timeline_ctx, strips_batch, strips);
1550
1551 /* Draw parts of strips above thumbnails. */
1553 for (const StripDrawContext &strip_ctx : strips) {
1554 draw_seq_fcurve_overlay(timeline_ctx, &strip_ctx);
1555 draw_seq_waveform_overlay(timeline_ctx, &strip_ctx);
1556 draw_multicam_highlight(timeline_ctx, &strip_ctx);
1557 draw_handle_transform_text(timeline_ctx, &strip_ctx, STRIP_HANDLE_LEFT);
1558 draw_handle_transform_text(timeline_ctx, &strip_ctx, STRIP_HANDLE_RIGHT);
1559 draw_seq_text_overlay(timeline_ctx, &strip_ctx);
1560 sequencer_retiming_speed_draw(timeline_ctx, strip_ctx);
1561 }
1562 timeline_ctx->quads->draw();
1563
1564 /* Draw retiming continuity ranges. */
1565 draw_retiming_continuity_ranges(timeline_ctx, strips);
1566 sequencer_retiming_keys_draw(timeline_ctx, strips);
1567
1568 draw_strips_foreground(timeline_ctx, strips_batch, strips);
1569
1570 /* Draw icons. */
1571 draw_strip_icons(timeline_ctx, strips);
1572
1573 /* Draw text labels. */
1574 UI_view2d_text_cache_draw(timeline_ctx->region);
1576}
1577
1578static void draw_seq_strips(TimelineDrawContext *timeline_ctx, StripsDrawBatch &strips_batch)
1579{
1580 if (timeline_ctx->ed == nullptr) {
1581 return;
1582 }
1583
1584 /* Discard thumbnail requests that are far enough from viewing area:
1585 * by +- 30 frames and +-2 channels outside of current view. */
1586 rctf rect = timeline_ctx->v2d->cur;
1587 rect.xmin -= 30;
1588 rect.xmax += 30;
1589 rect.ymin -= 2;
1590 rect.ymax += 2;
1593
1594 Vector<StripDrawContext> bottom_layer, top_layer;
1595 visible_strips_ordered_get(timeline_ctx, bottom_layer, top_layer);
1596 draw_seq_strips(timeline_ctx, strips_batch, bottom_layer);
1597 draw_seq_strips(timeline_ctx, strips_batch, top_layer);
1598}
1599
1601{
1602 const Scene *scene = ctx->scene;
1603 const View2D *v2d = ctx->v2d;
1604 const Editing *ed = seq::editing_get(scene);
1605 const int frame_sta = scene->r.sfra;
1606 const int frame_end = scene->r.efra + 1;
1607
1609
1612
1613 /* Draw overlay outside of frame range. */
1615
1616 if (frame_sta < frame_end) {
1617 immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, float(frame_sta), v2d->cur.ymax);
1618 immRectf(pos, float(frame_end), v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
1619 }
1620 else {
1621 immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
1622 }
1623
1625
1626 /* Draw frame range boundary. */
1628
1629 immVertex2f(pos, frame_sta, v2d->cur.ymin);
1630 immVertex2f(pos, frame_sta, v2d->cur.ymax);
1631
1632 immVertex2f(pos, frame_end, v2d->cur.ymin);
1633 immVertex2f(pos, frame_end, v2d->cur.ymax);
1634
1635 immEnd();
1636
1637 /* While in meta strip, draw a checkerboard overlay outside of frame range. */
1638 if (ed && !BLI_listbase_is_empty(&ed->metastack)) {
1639 const MetaStack *ms = static_cast<const MetaStack *>(ed->metastack.last);
1641
1643
1644 immUniform4f("color1", 0.0f, 0.0f, 0.0f, 0.22f);
1645 immUniform4f("color2", 1.0f, 1.0f, 1.0f, 0.0f);
1646 immUniform1i("size", 8);
1647
1648 immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, ms->disp_range[0], v2d->cur.ymax);
1649 immRectf(pos, ms->disp_range[1], v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
1650
1652
1655
1657
1658 immVertex2f(pos, ms->disp_range[0], v2d->cur.ymin);
1659 immVertex2f(pos, ms->disp_range[0], v2d->cur.ymax);
1660
1661 immVertex2f(pos, ms->disp_range[1], v2d->cur.ymin);
1662 immVertex2f(pos, ms->disp_range[1], v2d->cur.ymax);
1663
1664 immEnd();
1665 }
1666
1668
1670}
1671
1678
1679/* Draw final cache entries on top of the timeline. */
1680static void draw_cache_final_iter_fn(void *userdata, int timeline_frame)
1681{
1682 CacheDrawData *drawdata = static_cast<CacheDrawData *>(userdata);
1683
1684 /* Same as movie clip cache color, see ED_region_cache_draw_cached_segments. */
1685 const uchar4 col{108, 108, 210, 255};
1686
1687 const View2D *v2d = drawdata->v2d;
1688 float stripe_top = v2d->cur.ymax - (UI_TIME_SCRUB_MARGIN_Y / UI_view2d_scale_get_y(v2d));
1689 float stripe_bot = stripe_top - (UI_TIME_CACHE_MARGIN_Y / UI_view2d_scale_get_y(v2d));
1690 drawdata->quads->add_quad(timeline_frame, stripe_bot, timeline_frame + 1, stripe_top, col);
1691}
1692
1693/* Draw source cache entries at bottom of the strips. */
1694static void draw_cache_source_iter_fn(void *userdata, const Strip *strip, int timeline_frame)
1695{
1696 CacheDrawData *drawdata = static_cast<CacheDrawData *>(userdata);
1697
1698 const uchar4 col{255, 25, 5, 100};
1699 float stripe_bot = strip->channel + STRIP_OFSBOTTOM + drawdata->stripe_ofs_y;
1700 float stripe_top = stripe_bot + drawdata->stripe_ht;
1701 drawdata->quads->add_quad(timeline_frame, stripe_bot, timeline_frame + 1, stripe_top, col);
1702}
1703
1704static void draw_cache_stripe(const Scene *scene,
1705 const Strip *strip,
1706 SeqQuadsBatch &quads,
1707 const float stripe_bot,
1708 const float stripe_ht,
1709 const uchar color[4])
1710{
1711 quads.add_quad(seq::time_left_handle_frame_get(scene, strip),
1712 stripe_bot,
1714 stripe_bot + stripe_ht,
1715 color);
1716}
1717
1718static void draw_cache_background(const bContext *C, CacheDrawData *draw_data)
1719{
1720 const Scene *scene = CTX_data_scene(C);
1721 const View2D *v2d = UI_view2d_fromcontext(C);
1722 const SpaceSeq *sseq = CTX_wm_space_seq(C);
1723
1724 /* NOTE: Final bg color is the same as the movie clip cache color.
1725 * See ED_region_cache_draw_background.
1726 */
1727 const uchar4 bg_final{78, 78, 145, 255};
1728 const uchar4 bg_raw{255, 25, 5, 25};
1729
1730 float stripe_bot;
1731 bool dev_ui = (U.flag & USER_DEVELOPER_UI);
1732
1734 /* Draw the final cache on top of the timeline */
1735 float stripe_top = v2d->cur.ymax - (UI_TIME_SCRUB_MARGIN_Y / UI_view2d_scale_get_y(v2d));
1736 stripe_bot = stripe_top - (UI_TIME_CACHE_MARGIN_Y / UI_view2d_scale_get_y(v2d));
1737
1738 draw_data->quads->add_quad(scene->r.sfra, stripe_bot, scene->r.efra, stripe_top, bg_final);
1739 }
1740
1741 if (!dev_ui) {
1742 /* Don't show these cache types below unless developer extras is on. */
1743 return;
1744 }
1745
1747 strips.remove_if([&](Strip *strip) { return strip->type == STRIP_TYPE_SOUND_RAM; });
1748
1749 for (const Strip *strip : strips) {
1750 stripe_bot = strip->channel + STRIP_OFSBOTTOM + draw_data->stripe_ofs_y;
1752 draw_cache_stripe(scene, strip, *draw_data->quads, stripe_bot, draw_data->stripe_ht, bg_raw);
1753 }
1754 }
1755}
1756
1757static void draw_cache_view(const bContext *C)
1758{
1759 Scene *scene = CTX_data_scene(C);
1760 const View2D *v2d = UI_view2d_fromcontext(C);
1761 const SpaceSeq *sseq = CTX_wm_space_seq(C);
1762
1763 if ((sseq->flag & SEQ_SHOW_OVERLAY) == 0 || (sseq->cache_overlay.flag & SEQ_CACHE_SHOW) == 0) {
1764 return;
1765 }
1766
1767 float stripe_ofs_y = UI_view2d_region_to_view_y(v2d, 1.0f) - v2d->cur.ymin;
1768 float stripe_ht = UI_view2d_region_to_view_y(v2d, 4.0f * UI_SCALE_FAC * U.pixelsize) -
1769 v2d->cur.ymin;
1770
1771 CLAMP_MAX(stripe_ht, 0.2f);
1772 CLAMP_MIN(stripe_ofs_y, stripe_ht / 2);
1773
1774 SeqQuadsBatch quads;
1775 CacheDrawData userdata;
1776 userdata.v2d = v2d;
1777 userdata.stripe_ofs_y = stripe_ofs_y;
1778 userdata.stripe_ht = stripe_ht;
1779 userdata.quads = &quads;
1780
1782
1783 draw_cache_background(C, &userdata);
1786 }
1787 if ((U.flag & USER_DEVELOPER_UI) && (sseq->cache_overlay.flag & SEQ_CACHE_SHOW_RAW)) {
1789 }
1790
1791 quads.draw();
1793}
1794
1795/* Draw sequencer timeline. */
1796static void draw_overlap_frame_indicator(const Scene *scene, const View2D *v2d)
1797{
1798 int overlap_frame = (scene->ed->overlay_frame_flag & SEQ_EDIT_OVERLAY_FRAME_ABS) ?
1799 scene->ed->overlay_frame_abs :
1800 scene->r.cfra + scene->ed->overlay_frame_ofs;
1801
1804 float viewport_size[4];
1805 GPU_viewport_size_get_f(viewport_size);
1806 immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
1807 /* Shader may have color set from past usage - reset it. */
1808 immUniform1i("colors_len", 0);
1809 immUniform1f("dash_width", 20.0f * U.pixelsize);
1810 immUniform1f("udash_factor", 0.5f);
1812
1814 immVertex2f(pos, overlap_frame, v2d->cur.ymin);
1815 immVertex2f(pos, overlap_frame, v2d->cur.ymax);
1816 immEnd();
1817
1819}
1820
1822{
1823 if ((ctx->sseq->flag & SEQ_SHOW_OVERLAY) == 0 ||
1825 {
1826 return;
1827 }
1828
1829 U.v2d_min_gridsize *= 3;
1831 ctx->v2d, ctx->scene, (ctx->sseq->flag & SEQ_DRAWFRAMES) == 0, false);
1832 U.v2d_min_gridsize /= 3;
1833}
1834
1836{
1837 if ((ctx->sseq->flag & SEQ_SHOW_MARKERS) == 0) {
1838 return;
1839 }
1840
1841 UI_view2d_view_orthoSpecial(ctx->region, ctx->v2d, true);
1843}
1844
1846{
1847 if ((ctx->sseq->gizmo_flag & SEQ_GIZMO_HIDE) != 0) {
1848 return;
1849 }
1850
1851 WM_gizmomap_draw(ctx->region->runtime->gizmo_map, ctx->C, WM_GIZMOMAP_DRAWSTEP_2D);
1852}
1853
1862
1869
1871{
1872 SeqQuadsBatch quads_batch;
1873 TimelineDrawContext ctx = timeline_draw_context_get(C, &quads_batch);
1874 StripsDrawBatch strips_batch(ctx.v2d);
1875
1879 draw_timeline_grid(&ctx);
1881 draw_seq_strips(&ctx, strips_batch);
1882 if (region->winy > (UI_ANIM_MINY + UI_MARKER_MARGIN_Y)) {
1884 }
1886 ANIM_draw_previewrange(ctx.scene, ctx.v2d, 1);
1889 ED_time_scrub_draw(region, ctx.scene, !(ctx.sseq->flag & SEQ_DRAWFRAMES), true);
1890
1892}
1893
1895{
1896 const Scene *scene = CTX_data_scene(C);
1897 const SpaceSeq *sseq = CTX_wm_space_seq(C);
1898 View2D *v2d = &region->v2d;
1899
1900 if (scene->ed != nullptr) {
1904 draw_overlap_frame_indicator(scene, v2d);
1905 }
1907 }
1908
1910 region, scene, !(sseq->flag & SEQ_DRAWFRAMES), region->winy >= UI_ANIM_MINY);
1911
1912 if (region->winy > UI_ANIM_MINY) {
1913 const ListBase *seqbase = seq::active_seqbase_get(seq::editing_get(scene));
1914 seq::timeline_boundbox(scene, seqbase, &v2d->tot);
1915 const rcti scroller_mask = ED_time_scrub_clamp_scroller_mask(v2d->mask);
1916 region->v2d.scroll |= V2D_SCROLL_BOTTOM;
1917 UI_view2d_scrollers_draw(v2d, &scroller_mask);
1918 }
1919 else {
1920 region->v2d.scroll &= ~V2D_SCROLL_BOTTOM;
1921 }
1922}
1923
1924} // namespace blender::ed::vse
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: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:805
#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)
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: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
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:599
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:600
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
@ RGN_TYPE_WINDOW
#define STRIP_OFSBOTTOM
@ SEQ_SHOW_OFFSETS
@ SEQ_SCENE_STRIPS
@ SEQ_OVERLAP
@ SEQ_AUDIO_DRAW_WAVEFORM
#define STRIP_OFSTOP
@ 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_TRANSFORM
@ 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
@ 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_MARKERS
@ SEQ_SHOW_OVERLAY
@ SEQ_GIZMO_HIDE
#define UI_SCALE_FAC
#define UI_INV_SCALE_FAC
@ USER_DEVELOPER_UI
@ USER_SEQ_ED_SIMPLE_TWEAKING
@ V2D_SCROLL_BOTTOM
@ DRAW_MARKERS_MARGIN
Definition ED_markers.hh:27
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 *fb)
void GPU_framebuffer_bind(GPUFrameBuffer *fb)
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:111
void GPU_depth_test(eGPUDepthTest test)
Definition gpu_state.cc:68
void GPU_viewport_size_get_f(float coords[4])
Definition gpu_state.cc:273
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, blender::StringRef name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
GPUFrameBuffer * 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:473
#define UI_MARKER_MARGIN_Y
Definition UI_view2d.hh:470
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:2081
void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
Definition view2d.cc:1503
#define UI_TIME_CACHE_MARGIN_Y
Definition UI_view2d.hh:472
void UI_view2d_view_restore(const bContext *C)
Definition view2d.cc:1162
void UI_view2d_text_cache_draw(ARegion *region)
Definition view2d.cc:2141
float UI_view2d_region_to_view_y(const View2D *v2d, float y)
Definition view2d.cc:1661
#define UI_TIME_SCRUB_MARGIN_Y
Definition UI_view2d.hh:471
void UI_view2d_text_cache_add_rectf(View2D *v2d, const rctf *rect_view, const char *str, size_t str_len, const unsigned char col[4])
Definition view2d.cc:2111
void 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:1854
float UI_view2d_scale_get_y(const View2D *v2d)
Definition view2d.cc:1924
@ WM_GIZMOMAP_DRAWSTEP_2D
#define ND_SEQUENCER
Definition WM_types.hh:434
#define NC_SCENE
Definition WM_types.hh:375
void ANIM_draw_previewrange(const Scene *scene, View2D *v2d, int end_frame_width)
Definition anim_draw.cc:75
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:2092
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:599
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:272
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:420
ListBase * get_seqbase_from_strip(Strip *strip, ListBase **r_channels, int *r_offset)
eSeqOverlapMode tool_settings_overlap_mode_get(Scene *scene)
Definition sequencer.cc:408
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
ARegionRuntimeHandle * runtime
char name[66]
Definition DNA_ID.h:415
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
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::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_current_frame(const ARegion *region, const Scene *scene, bool display_seconds, bool display_stalk)
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:912
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)