diff --git a/source/blender/editors/space_sequencer/sequencer_thumbnails.cc b/source/blender/editors/space_sequencer/sequencer_thumbnails.cc index 903c17699d8..61192e8ac15 100644 --- a/source/blender/editors/space_sequencer/sequencer_thumbnails.cc +++ b/source/blender/editors/space_sequencer/sequencer_thumbnails.cc @@ -435,6 +435,14 @@ void draw_seq_strip_thumbnail(View2D *v2d, float pixelx, float pixely) { + SpaceSeq *sseq = CTX_wm_space_seq(C); + if ((sseq->flag & SEQ_SHOW_OVERLAY) == 0 || + (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_THUMBNAILS) == 0 || + !ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE)) + { + return; + } + bool clipped = false; float image_height, image_width, thumb_width; rcti crop; diff --git a/source/blender/editors/space_sequencer/sequencer_timeline_draw.cc b/source/blender/editors/space_sequencer/sequencer_timeline_draw.cc index 0464130dbd5..ef47f7ea4c0 100644 --- a/source/blender/editors/space_sequencer/sequencer_timeline_draw.cc +++ b/source/blender/editors/space_sequencer/sequencer_timeline_draw.cc @@ -79,6 +79,152 @@ static Sequence *special_seq_update = nullptr; +typedef struct StripDrawContext { + Sequence *seq; + float content_start, content_end, bottom, top; /* Strip boundary in timeline space. */ + float left_handle, right_handle; /* Position in frames. */ + float strip_content_top; /* Position in timeline space deliminates content and text overlay. */ + float handle_width; /* Width of strip handle in frames. */ + + bool can_draw_text_overlay; + bool can_draw_strip_content; + bool is_too_small; /* Shorthand for (!can_draw_text_overlay && !can_draw_strip_content). */ + bool is_active_strip; + bool is_single_image; /* Strip has single frame of content. */ + bool show_strip_color_tag; +} StripDrawContext; + +typedef struct TimelineDrawContext { + const bContext *C; + ARegion *region; + Scene *scene; + SpaceSeq *sseq; + View2D *v2d; + Editing *ed; + ListBase *channels; + GPUViewport *viewport; + GPUFrameBuffer *framebuffer_overlay; + float pixelx, pixely; /* Width and height of pixel in timeline space. */ +} TimelineDrawContext; + +static TimelineDrawContext timeline_draw_context_get(const bContext *C) +{ + TimelineDrawContext ctx; + + ctx.C = C; + ctx.region = CTX_wm_region(C); + ctx.scene = CTX_data_scene(C); + ctx.sseq = CTX_wm_space_seq(C); + ctx.v2d = UI_view2d_fromcontext(C); + + ctx.ed = SEQ_editing_get(ctx.scene); + ctx.channels = SEQ_channels_displayed_get(ctx.ed); + + ctx.viewport = WM_draw_region_get_viewport(ctx.region); + ctx.framebuffer_overlay = GPU_viewport_framebuffer_overlay_get(ctx.viewport); + + ctx.pixely = BLI_rctf_size_y(&ctx.v2d->cur) / BLI_rcti_size_y(&ctx.v2d->mask); + ctx.pixelx = BLI_rctf_size_x(&ctx.v2d->cur) / BLI_rcti_size_x(&ctx.v2d->mask); + + return ctx; +} + +static bool seq_draw_waveforms_poll(const bContext * /*C*/, SpaceSeq *sseq, Sequence *seq) +{ + const bool strip_is_valid = seq->type == SEQ_TYPE_SOUND_RAM && seq->sound != nullptr; + const bool overlays_enabled = (sseq->flag & SEQ_SHOW_OVERLAY) != 0; + const bool ovelay_option = ((sseq->timeline_overlay.flag & SEQ_TIMELINE_ALL_WAVEFORMS) != 0 || + (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM)); + + if ((sseq->timeline_overlay.flag & SEQ_TIMELINE_NO_WAVEFORMS) != 0) { + return false; + } + + if (strip_is_valid && overlays_enabled && ovelay_option) { + return true; + } + + return false; +} + +static bool strip_hides_text_overlay_first(TimelineDrawContext *ctx, StripDrawContext *strip_ctx) +{ + return seq_draw_waveforms_poll(ctx->C, ctx->sseq, strip_ctx->seq) || + strip_ctx->seq->type == SEQ_TYPE_COLOR; +} + +static void strip_draw_context_set_text_overlay_visibility(TimelineDrawContext *ctx, + StripDrawContext *strip_ctx) +{ + float threshold = 8 * ctx->pixely * UI_SCALE_FAC; + if (strip_hides_text_overlay_first(ctx, strip_ctx)) { + threshold = 20 * UI_SCALE_FAC; + } + + const bool overlays_enabled = (ctx->sseq->timeline_overlay.flag & + (SEQ_TIMELINE_SHOW_STRIP_NAME | SEQ_TIMELINE_SHOW_STRIP_SOURCE | + SEQ_TIMELINE_SHOW_STRIP_DURATION)) != 0; + + strip_ctx->can_draw_text_overlay = (strip_ctx->top - strip_ctx->bottom) / ctx->pixely >= + threshold; + strip_ctx->can_draw_text_overlay &= overlays_enabled; +} + +static void strip_draw_context_set_strip_content_visibility(TimelineDrawContext *ctx, + StripDrawContext *strip_ctx) +{ + float threshold = 20 * UI_SCALE_FAC; + if (strip_hides_text_overlay_first(ctx, strip_ctx)) { + threshold = 8 * ctx->pixely * UI_SCALE_FAC; + } + + strip_ctx->can_draw_strip_content = ((strip_ctx->top - strip_ctx->bottom) / ctx->pixely) > + threshold; +} + +static StripDrawContext strip_draw_context_get(TimelineDrawContext *ctx, Sequence *seq) +{ + StripDrawContext strip_ctx; + Scene *scene = ctx->scene; + + strip_ctx.seq = seq; + strip_ctx.bottom = seq->machine + SEQ_STRIP_OFSBOTTOM; + strip_ctx.top = seq->machine + SEQ_STRIP_OFSTOP; + strip_ctx.content_start = SEQ_time_left_handle_frame_get(scene, seq); + strip_ctx.content_end = SEQ_time_right_handle_frame_get(scene, seq); + if (SEQ_time_has_left_still_frames(scene, seq)) { + SEQ_time_start_frame_get(seq); + } + if (SEQ_time_has_right_still_frames(scene, seq)) { + SEQ_time_content_end_frame_get(scene, seq); + } + /* Limit body to strip bounds. Meta strip can end up with content outside of strip range. */ + strip_ctx.content_start = min_ff(strip_ctx.content_start, + SEQ_time_right_handle_frame_get(scene, seq)); + strip_ctx.content_end = max_ff(strip_ctx.content_end, + SEQ_time_left_handle_frame_get(scene, seq)); + strip_ctx.left_handle = SEQ_time_left_handle_frame_get(scene, seq); + strip_ctx.right_handle = SEQ_time_right_handle_frame_get(scene, seq); + + strip_draw_context_set_text_overlay_visibility(ctx, &strip_ctx); + strip_draw_context_set_strip_content_visibility(ctx, &strip_ctx); + strip_ctx.is_too_small = (!strip_ctx.can_draw_text_overlay && !strip_ctx.can_draw_strip_content); + strip_ctx.is_active_strip = seq == SEQ_select_active_get(scene); + strip_ctx.is_single_image = SEQ_transform_single_image_check(seq); + strip_ctx.handle_width = sequence_handle_size_get_clamped(ctx->scene, seq, ctx->pixelx); + strip_ctx.show_strip_color_tag = (ctx->sseq->timeline_overlay.flag & + SEQ_TIMELINE_SHOW_STRIP_COLOR_TAG); + + if (strip_ctx.can_draw_text_overlay) { + strip_ctx.strip_content_top = strip_ctx.top - min_ff(0.40f, 20 * UI_SCALE_FAC * ctx->pixely); + } + else { + strip_ctx.strip_content_top = strip_ctx.top; + } + + return strip_ctx; +} + void color3ubv_from_seq(const Scene *curscene, const Sequence *seq, const bool show_strip_color_tag, @@ -240,24 +386,6 @@ struct WaveVizData { bool final_sample; /* There are no more samples. */ }; -static bool seq_draw_waveforms_poll(const bContext * /*C*/, SpaceSeq *sseq, Sequence *seq) -{ - const bool strip_is_valid = seq->type == SEQ_TYPE_SOUND_RAM && seq->sound != nullptr; - const bool overlays_enabled = (sseq->flag & SEQ_SHOW_OVERLAY) != 0; - const bool ovelay_option = ((sseq->timeline_overlay.flag & SEQ_TIMELINE_ALL_WAVEFORMS) != 0 || - (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM)); - - if ((sseq->timeline_overlay.flag & SEQ_TIMELINE_NO_WAVEFORMS) != 0) { - return false; - } - - if (strip_is_valid && overlays_enabled && ovelay_option) { - return true; - } - - return false; -} - static void waveform_job_start_if_needed(const bContext *C, Sequence *seq) { bSound *sound = seq->sound; @@ -396,31 +524,34 @@ static size_t waveform_append_sample(WaveVizData *waveform_data, return data_written; } -/** - * \param x1, x2, y1, y2: The starting and end X value to draw the wave, same for y1 and y2. - * \param frames_per_pixel: The amount of pixels a whole frame takes up (x-axis direction). - */ -static void draw_seq_waveform_overlay( - const bContext *C, ARegion *region, Sequence *seq, float x1, float y1, float x2, float y2) +static void draw_seq_waveform_overlay(TimelineDrawContext *timeline_ctx, + StripDrawContext *strip_ctx) { - const View2D *v2d = ®ion->v2d; - Scene *scene = CTX_data_scene(C); + if (!seq_draw_waveforms_poll(timeline_ctx->C, timeline_ctx->sseq, strip_ctx->seq) || + strip_ctx->is_too_small) + { + return; + } - const float frames_per_pixel = BLI_rctf_size_x(®ion->v2d.cur) / region->winx; + const View2D *v2d = timeline_ctx->v2d; + Scene *scene = timeline_ctx->scene; + Sequence *seq = strip_ctx->seq; + + const float frames_per_pixel = BLI_rctf_size_x(&v2d->cur) / timeline_ctx->region->winx; const float samples_per_frame = SOUND_WAVE_SAMPLES_PER_SECOND / FPS; /* Align strip start with nearest pixel to prevent waveform flickering. */ - const float x1_aligned = align_frame_with_pixel(x1, frames_per_pixel); + const float x1_aligned = align_frame_with_pixel(strip_ctx->content_start, frames_per_pixel); /* Offset x1 and x2 values, to match view min/max, if strip is out of bounds. */ const float frame_start = max_ff(v2d->cur.xmin, x1_aligned); - const float frame_end = min_ff(v2d->cur.xmax, x2); + const float frame_end = min_ff(v2d->cur.xmax, strip_ctx->right_handle); const int pixels_to_draw = round_fl_to_int((frame_end - frame_start) / frames_per_pixel); if (pixels_to_draw < 2) { return; /* Not much to draw, exit before running job. */ } - waveform_job_start_if_needed(C, seq); + waveform_job_start_if_needed(timeline_ctx->C, seq); SoundWaveform *waveform = static_cast(seq->sound->waveform); if (waveform == nullptr || waveform->length == 0) { @@ -501,9 +632,9 @@ static void draw_seq_waveform_overlay( bool is_line_strip = (value_max - value_min < 0.05f); /* The y coordinate for the middle of the strip. */ - float y_mid = (y1 + y2) / 2.0f; + float y_mid = (strip_ctx->bottom + strip_ctx->strip_content_top) / 2.0f; /* The length from the middle of the strip to the top/bottom. */ - float y_scale = (y2 - y1) / 2.0f; + float y_scale = (strip_ctx->strip_content_top - strip_ctx->bottom) / 2.0f; vec2f pos = {frame_start + i * frames_per_pixel, y_mid + value_min * y_scale}; WaveVizData *new_data = &waveform_data[wave_data_len]; @@ -517,20 +648,26 @@ static void draw_seq_waveform_overlay( MEM_freeN(waveform_data); } -static void drawmeta_contents(Scene *scene, - Sequence *seqm, - float x1, - float y1, - float x2, - float y2, - const bool show_strip_color_tag) +static void drawmeta_contents(TimelineDrawContext *timeline_ctx, StripDrawContext *strip_ctx) { + Sequence *seq_meta = strip_ctx->seq; + if (!strip_ctx->can_draw_strip_content || (timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) == 0) { + return; + } + if ((seq_meta->type != SEQ_TYPE_META) && + ((seq_meta->type != SEQ_TYPE_SCENE) || (seq_meta->flag & SEQ_SCENE_STRIPS) == 0)) + { + return; + } + + Scene *scene = timeline_ctx->scene; + uchar col[4]; int chan_min = MAXSEQ; int chan_max = 0; int chan_range = 0; - float draw_range = y2 - y1; + float draw_range = strip_ctx->top - strip_ctx->bottom; float draw_height; Editing *ed = SEQ_editing_get(scene); @@ -539,14 +676,14 @@ static void drawmeta_contents(Scene *scene, ListBase *meta_channels; int offset; - meta_seqbase = SEQ_get_seqbase_from_sequence(seqm, &meta_channels, &offset); + meta_seqbase = SEQ_get_seqbase_from_sequence(seq_meta, &meta_channels, &offset); if (!meta_seqbase || BLI_listbase_is_empty(meta_seqbase)) { return; } - if (seqm->type == SEQ_TYPE_SCENE) { - offset = seqm->start - offset; + if (seq_meta->type == SEQ_TYPE_SCENE) { + offset = seq_meta->start - offset; } else { offset = 0; @@ -572,7 +709,7 @@ static void drawmeta_contents(Scene *scene, const int startdisp = SEQ_time_left_handle_frame_get(scene, seq) + offset; const int enddisp = SEQ_time_right_handle_frame_get(scene, seq) + offset; - if ((startdisp > x2 || enddisp < x1) == 0) { + if ((startdisp > strip_ctx->right_handle || enddisp < strip_ctx->left_handle) == 0) { float y_chan = (seq->machine - chan_min) / float(chan_range) * draw_range; float x1_chan = startdisp; float x2_chan = enddisp; @@ -583,10 +720,10 @@ static void drawmeta_contents(Scene *scene, rgb_float_to_uchar(col, colvars->col); } else { - color3ubv_from_seq(scene, seq, show_strip_color_tag, col); + color3ubv_from_seq(scene, seq, strip_ctx->show_strip_color_tag, col); } - if (SEQ_render_is_muted(channels, seqm) || SEQ_render_is_muted(meta_channels, seq)) { + if (SEQ_render_is_muted(channels, seq_meta) || SEQ_render_is_muted(meta_channels, seq)) { col[3] = 64; } else { @@ -596,15 +733,15 @@ static void drawmeta_contents(Scene *scene, immUniformColor4ubv(col); /* Clamp within parent sequence strip bounds. */ - if (x1_chan < x1) { - x1_chan = x1; + if (x1_chan < strip_ctx->left_handle) { + x1_chan = strip_ctx->left_handle; } - if (x2_chan > x2) { - x2_chan = x2; + if (x2_chan > strip_ctx->right_handle) { + x2_chan = strip_ctx->right_handle; } - y1_chan = y1 + y_chan + (draw_height * SEQ_STRIP_OFSBOTTOM); - y2_chan = y1 + y_chan + (draw_height * SEQ_STRIP_OFSTOP); + y1_chan = strip_ctx->bottom + y_chan + (draw_height * SEQ_STRIP_OFSBOTTOM); + y2_chan = strip_ctx->bottom + y_chan + (draw_height * SEQ_STRIP_OFSTOP); immRectf(pos, x1_chan, y1_chan, x2_chan, y2_chan); } @@ -627,46 +764,39 @@ float sequence_handle_size_get_clamped(const Scene *scene, Sequence *seq, const } /* Draw a handle, on left or right side of strip. */ -static void draw_seq_handle(const Scene *scene, - View2D *v2d, - Sequence *seq, - const float handsize_clamped, - const short direction, - uint pos, - bool seq_active, - float pixelx, - const bool draw_strip_preview) +static void draw_seq_handle(TimelineDrawContext *timeline_ctx, + StripDrawContext *strip_ctx, + const short direction) { + Sequence *seq = strip_ctx->seq; + + if (SEQ_transform_is_locked(timeline_ctx->channels, seq)) { + return; + } + float rx1 = 0, rx2 = 0; - float x1, x2, y1, y2; uint whichsel = 0; uchar col[4]; - x1 = SEQ_time_left_handle_frame_get(scene, seq); - x2 = SEQ_time_right_handle_frame_get(scene, seq); - - y1 = seq->machine + SEQ_STRIP_OFSBOTTOM; - y2 = seq->machine + SEQ_STRIP_OFSTOP; - /* Set up co-ordinates and dimensions for either left or right handle. */ if (direction == SEQ_LEFTHANDLE) { - rx1 = x1; - rx2 = x1 + handsize_clamped; + rx1 = strip_ctx->left_handle; + rx2 = strip_ctx->left_handle + strip_ctx->handle_width; whichsel = SEQ_LEFTSEL; } else if (direction == SEQ_RIGHTHANDLE) { - rx1 = x2 - handsize_clamped; - rx2 = x2; + rx1 = strip_ctx->right_handle - strip_ctx->handle_width; + rx2 = strip_ctx->right_handle; whichsel = SEQ_RIGHTSEL; } if (!(seq->type & SEQ_TYPE_EFFECT) || SEQ_effect_get_num_inputs(seq->type) == 0) { - GPU_blend(GPU_BLEND_ALPHA); - + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); GPU_blend(GPU_BLEND_ALPHA); if (seq->flag & whichsel) { - if (seq_active) { + if (strip_ctx->is_active_strip) { UI_GetThemeColor3ubv(TH_SEQ_ACTIVE, col); } else { @@ -681,12 +811,13 @@ static void draw_seq_handle(const Scene *scene, immUniformColor4ub(0, 0, 0, 50); } - immRectf(pos, rx1, y1, rx2, y2); + immRectf(pos, rx1, strip_ctx->bottom, rx2, strip_ctx->top); GPU_blend(GPU_BLEND_NONE); + immUnbindProgram(); } /* Draw numbers for start and end of the strip next to its handles. */ - if (draw_strip_preview && + if (strip_ctx->can_draw_strip_content && (((seq->flag & SELECT) && (G.moving & G_TRANSFORM_SEQ)) || (seq->flag & whichsel))) { @@ -696,46 +827,42 @@ static void draw_seq_handle(const Scene *scene, BLF_set_default(); /* Calculate if strip is wide enough for showing the labels. */ - numstr_len = SNPRINTF_RLEN(numstr, - "%d%d", - SEQ_time_left_handle_frame_get(scene, seq), - SEQ_time_right_handle_frame_get(scene, seq)); + numstr_len = SNPRINTF_RLEN( + numstr, "%d%d", int(strip_ctx->left_handle), int(strip_ctx->right_handle)); float tot_width = BLF_width(fontid, numstr, numstr_len); - if ((x2 - x1) / pixelx > 20 + tot_width) { + if ((strip_ctx->right_handle - strip_ctx->left_handle) / timeline_ctx->pixelx > 20 + tot_width) + { col[0] = col[1] = col[2] = col[3] = 255; - float text_margin = 1.2f * handsize_clamped; + float text_margin = 1.2f * strip_ctx->handle_width; + float text_x = strip_ctx->left_handle; + const float text_y = strip_ctx->bottom + 0.09f; if (direction == SEQ_LEFTHANDLE) { - numstr_len = SNPRINTF_RLEN(numstr, "%d", SEQ_time_left_handle_frame_get(scene, seq)); - x1 += text_margin; - y1 += 0.09f; + numstr_len = SNPRINTF_RLEN(numstr, "%d", int(strip_ctx->left_handle)); + text_x += text_margin; } else { - numstr_len = SNPRINTF_RLEN(numstr, "%d", SEQ_time_right_handle_frame_get(scene, seq) - 1); - x1 = x2 - (text_margin + pixelx * BLF_width(fontid, numstr, numstr_len)); - y1 += 0.09f; + numstr_len = SNPRINTF_RLEN(numstr, "%d", int(strip_ctx->right_handle - 1)); + text_x = strip_ctx->right_handle - + (text_margin + timeline_ctx->pixelx * BLF_width(fontid, numstr, numstr_len)); } - UI_view2d_text_cache_add(v2d, x1, y1, numstr, numstr_len, col); + UI_view2d_text_cache_add(timeline_ctx->v2d, text_x, text_y, numstr, numstr_len, col); } } } -static void draw_seq_outline(Scene *scene, - Sequence *seq, - uint pos, - float x1, - float x2, - float y1, - float y2, - float pixelx, - float pixely, - bool seq_active) +static void draw_seq_outline(TimelineDrawContext *timeline_ctx, StripDrawContext *strip_ctx) { + + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + + Sequence *seq = strip_ctx->seq; uchar col[3]; /* Get the color for the outline. */ - if (seq_active && (seq->flag & SELECT)) { + if (strip_ctx->is_active_strip && (seq->flag & SELECT)) { UI_GetThemeColor3ubv(TH_SEQ_ACTIVE, col); } else if (seq->flag & SELECT) { @@ -750,7 +877,7 @@ static void draw_seq_outline(Scene *scene, * - Slightly lighter. * - Red when overlapping with other strips. */ - const eSeqOverlapMode overlap_mode = SEQ_tool_settings_overlap_mode_get(scene); + const eSeqOverlapMode overlap_mode = SEQ_tool_settings_overlap_mode_get(timeline_ctx->scene); if ((G.moving & G_TRANSFORM_SEQ) && (seq->flag & SELECT) && overlap_mode != SEQ_OVERLAP_OVERWRITE) { if (seq->flag & SEQ_OVERLAP) { @@ -768,18 +895,36 @@ static void draw_seq_outline(Scene *scene, * draw outline as four boxes instead. */ if (seq->flag & SELECT) { /* Left */ - immRectf(pos, x1 - pixelx, y1, x1 + pixelx, y2); + immRectf(pos, + strip_ctx->left_handle - timeline_ctx->pixelx, + strip_ctx->bottom, + strip_ctx->left_handle + timeline_ctx->pixelx, + strip_ctx->top); /* Bottom */ - immRectf(pos, x1 - pixelx, y1, x2 + pixelx, y1 + 2 * pixely); + immRectf(pos, + strip_ctx->left_handle - timeline_ctx->pixelx, + strip_ctx->bottom, + strip_ctx->right_handle + timeline_ctx->pixelx, + strip_ctx->bottom + 2 * timeline_ctx->pixely); /* Right */ - immRectf(pos, x2 - pixelx, y1, x2 + pixelx, y2); + immRectf(pos, + strip_ctx->right_handle - timeline_ctx->pixelx, + strip_ctx->bottom, + strip_ctx->right_handle + timeline_ctx->pixelx, + strip_ctx->top); /* Top */ - immRectf(pos, x1 - pixelx, y2 - 2 * pixely, x2 + pixelx, y2); + immRectf(pos, + strip_ctx->left_handle - timeline_ctx->pixelx, + strip_ctx->top - 2 * timeline_ctx->pixely, + strip_ctx->right_handle + timeline_ctx->pixelx, + strip_ctx->top); } else { /* 1px wide outline for unselected strips. */ - imm_draw_box_wire_2d(pos, x1, y1, x2, y2); + imm_draw_box_wire_2d( + pos, strip_ctx->left_handle, strip_ctx->bottom, strip_ctx->right_handle, strip_ctx->top); } + immUnbindProgram(); } static const char *draw_seq_text_get_name(Sequence *seq) @@ -848,22 +993,23 @@ static void draw_seq_text_get_source(Sequence *seq, char *r_source, size_t sourc } } -static size_t draw_seq_text_get_overlay_string(const Scene *scene, - SpaceSeq *sseq, - Sequence *seq, +static size_t draw_seq_text_get_overlay_string(TimelineDrawContext *timeline_ctx, + StripDrawContext *strip_ctx, char *r_overlay_string, size_t overlay_string_len) { + Sequence *seq = strip_ctx->seq; + const char *text_sep = " | "; const char *text_array[5]; int i = 0; - if (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_NAME) { + if (timeline_ctx->sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_NAME) { text_array[i++] = draw_seq_text_get_name(seq); } char source[FILE_MAX]; - if (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_SOURCE) { + if (timeline_ctx->sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_SOURCE) { draw_seq_text_get_source(seq, source, sizeof(source)); if (source[0] != '\0') { if (i != 0) { @@ -874,9 +1020,8 @@ static size_t draw_seq_text_get_overlay_string(const Scene *scene, } char strip_duration_text[16]; - if (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_DURATION) { - const int strip_duration = SEQ_time_right_handle_frame_get(scene, seq) - - SEQ_time_left_handle_frame_get(scene, seq); + if (timeline_ctx->sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_DURATION) { + const int strip_duration = strip_ctx->right_handle - strip_ctx->left_handle; SNPRINTF(strip_duration_text, "%d", strip_duration); if (i != 0) { text_array[i++] = text_sep; @@ -889,22 +1034,52 @@ static size_t draw_seq_text_get_overlay_string(const Scene *scene, return BLI_string_join_array(r_overlay_string, overlay_string_len, text_array, i); } -/* Draw info text on a sequence strip. */ -static void draw_seq_text_overlay(Scene *scene, - View2D *v2d, - Sequence *seq, - SpaceSeq *sseq, - float x1, - float x2, - float y1, - float y2, - bool seq_active) +/* For text on the strip. */ +static void calculate_seq_text_offsets(TimelineDrawContext *timeline_ctx, + StripDrawContext *strip_ctx, + float *x1, + float *x2) { - Editing *ed = SEQ_editing_get(scene); - ListBase *channels = SEQ_channels_displayed_get(ed); + float text_margin = 2.0f * strip_ctx->handle_width; + + *x1 += text_margin; + *x2 -= text_margin; + + CLAMP(*x1, timeline_ctx->v2d->cur.xmin + text_margin, timeline_ctx->v2d->cur.xmax); + CLAMP(*x2, timeline_ctx->v2d->cur.xmin + text_margin, timeline_ctx->v2d->cur.xmax); +} + +/* Draw info text on a sequence strip. */ +static void draw_seq_text_overlay(TimelineDrawContext *timeline_ctx, StripDrawContext *strip_ctx) +{ + /* If a waveform or a color strip is drawn, + * avoid drawing text when there is not enough vertical space. */ + if (!strip_ctx->can_draw_text_overlay && + (seq_draw_waveforms_poll(timeline_ctx->C, timeline_ctx->sseq, strip_ctx->seq) || + strip_ctx->seq->type == SEQ_TYPE_COLOR)) + { + return; + } + if ((timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) == 0) { + return; + } + /* Draw text only if there is enough horizontal or vertical space. */ + if (((strip_ctx->right_handle - strip_ctx->left_handle) <= + 32 * timeline_ctx->pixelx * UI_SCALE_FAC) || + strip_ctx->is_too_small) + { + return; + } + + /* Depending on the vertical space, draw text on top or in the center of strip. */ + float x1 = strip_ctx->left_handle, x2 = strip_ctx->right_handle; + calculate_seq_text_offsets(timeline_ctx, strip_ctx, &x1, &x2); + float y1 = !strip_ctx->can_draw_strip_content ? strip_ctx->bottom : + strip_ctx->strip_content_top; // Y1 + char overlay_string[FILE_MAX]; size_t overlay_string_len = draw_seq_text_get_overlay_string( - scene, sseq, seq, overlay_string, sizeof(overlay_string)); + timeline_ctx, strip_ctx, overlay_string, sizeof(overlay_string)); if (overlay_string_len == 0) { return; @@ -912,12 +1087,12 @@ static void draw_seq_text_overlay(Scene *scene, /* White text for the active strip. */ uchar col[4]; - col[0] = col[1] = col[2] = seq_active ? 255 : 10; + col[0] = col[1] = col[2] = strip_ctx->is_active_strip ? 255 : 10; col[3] = 255; /* Make the text duller when the strip is muted. */ - if (SEQ_render_is_muted(channels, seq)) { - if (seq_active) { + if (SEQ_render_is_muted(timeline_ctx->channels, strip_ctx->seq)) { + if (strip_ctx->is_active_strip) { UI_GetColorPtrShade3ubv(col, col, -70); } else { @@ -929,28 +1104,37 @@ static void draw_seq_text_overlay(Scene *scene, rect.xmin = x1; rect.ymin = y1; rect.xmax = x2; - rect.ymax = y2; + rect.ymax = strip_ctx->top; - UI_view2d_text_cache_add_rectf(v2d, &rect, overlay_string, overlay_string_len, col); + UI_view2d_text_cache_add_rectf( + timeline_ctx->v2d, &rect, overlay_string, overlay_string_len, col); } -static void draw_sequence_extensions_overlay( - Scene *scene, Sequence *seq, uint pos, float pixely, const bool show_strip_color_tag) +static void draw_strip_offsets(TimelineDrawContext *timeline_ctx, StripDrawContext *strip_ctx) { - Editing *ed = SEQ_editing_get(scene); - ListBase *channels = SEQ_channels_displayed_get(ed); - float x1, x2, y1, y2; - uchar col[4], blend_col[3]; + Sequence *seq = strip_ctx->seq; - x1 = SEQ_time_left_handle_frame_get(scene, seq); - x2 = SEQ_time_right_handle_frame_get(scene, seq); + if ((timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) == 0) { + return; + } + if (strip_ctx->is_single_image || timeline_ctx->pixely <= 0) { + return; + } + if ((timeline_ctx->sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_OFFSETS) == 0 && + (strip_ctx->seq != special_seq_update)) + { + return; + } - y1 = seq->machine + SEQ_STRIP_OFSBOTTOM; - y2 = seq->machine + SEQ_STRIP_OFSTOP; + Scene *scene = timeline_ctx->scene; + ListBase *channels = timeline_ctx->channels; + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); GPU_blend(GPU_BLEND_ALPHA); - color3ubv_from_seq(scene, seq, show_strip_color_tag, col); + uchar col[4], blend_col[3]; + color3ubv_from_seq(scene, seq, strip_ctx->show_strip_color_tag, col); if (seq->flag & SELECT) { UI_GetColorPtrShade3ubv(col, col, 50); } @@ -964,21 +1148,38 @@ static void draw_sequence_extensions_overlay( if (left_handle_frame > strip_content_start) { immUniformColor4ubv(col); - immRectf(pos, strip_content_start, y1 - pixely, x1, y1 - SEQ_STRIP_OFSBOTTOM); + immRectf(pos, + strip_content_start, + strip_ctx->bottom - timeline_ctx->pixely, + strip_ctx->content_start, + strip_ctx->bottom - SEQ_STRIP_OFSBOTTOM); /* Outline. */ immUniformColor3ubv(blend_col); - imm_draw_box_wire_2d(pos, x1, y1 - pixely, strip_content_start, y1 - SEQ_STRIP_OFSBOTTOM); + imm_draw_box_wire_2d(pos, + strip_ctx->content_start, + strip_ctx->bottom - timeline_ctx->pixely, + strip_content_start, + strip_ctx->bottom - SEQ_STRIP_OFSBOTTOM); } if (right_handle_frame < strip_content_end) { immUniformColor4ubv(col); - immRectf(pos, x2, y2 + pixely, strip_content_end, y2 + SEQ_STRIP_OFSBOTTOM); + immRectf(pos, + strip_ctx->content_end, + strip_ctx->top + timeline_ctx->pixely, + strip_content_end, + strip_ctx->top + SEQ_STRIP_OFSBOTTOM); /* Outline. */ immUniformColor3ubv(blend_col); - imm_draw_box_wire_2d(pos, x2, y2 + pixely, strip_content_end, y2 + SEQ_STRIP_OFSBOTTOM); + imm_draw_box_wire_2d(pos, + strip_ctx->content_end, + strip_ctx->top + timeline_ctx->pixely, + strip_content_end, + strip_ctx->top + SEQ_STRIP_OFSBOTTOM); } GPU_blend(GPU_BLEND_NONE); + immUnbindProgram(); } static uchar mute_overlap_alpha_factor_get(const ListBase *channels, const Sequence *seq) @@ -996,88 +1197,92 @@ static uchar mute_overlap_alpha_factor_get(const ListBase *channels, const Seque } } -static void draw_color_strip_band( - const Scene *scene, ListBase *channels, Sequence *seq, uint pos, float text_margin_y, float y1) +static void draw_strip_color_band(TimelineDrawContext *timeline_ctx, StripDrawContext *strip_ctx) { - uchar col[4]; + Sequence *seq = strip_ctx->seq; + Scene *scene = timeline_ctx->scene; + + if ((timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) == 0 || (seq->type != SEQ_TYPE_COLOR)) { + return; + } + SolidColorVars *colvars = (SolidColorVars *)seq->effectdata; - - GPU_blend(GPU_BLEND_ALPHA); + uchar col[4]; rgb_float_to_uchar(col, colvars->col); + col[3] = mute_overlap_alpha_factor_get(timeline_ctx->channels, seq); - col[3] = mute_overlap_alpha_factor_get(channels, seq); - + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + GPU_blend(GPU_BLEND_ALPHA); immUniformColor4ubv(col); immRectf(pos, SEQ_time_left_handle_frame_get(scene, seq), - y1, + strip_ctx->bottom, SEQ_time_right_handle_frame_get(scene, seq), - text_margin_y); + strip_ctx->strip_content_top); /* 1px line to better separate the color band. */ UI_GetColorPtrShade3ubv(col, col, -20); immUniformColor4ubv(col); immBegin(GPU_PRIM_LINES, 2); - immVertex2f(pos, SEQ_time_left_handle_frame_get(scene, seq), text_margin_y); - immVertex2f(pos, SEQ_time_right_handle_frame_get(scene, seq), text_margin_y); + immVertex2f(pos, SEQ_time_left_handle_frame_get(scene, seq), strip_ctx->strip_content_top); + immVertex2f(pos, SEQ_time_right_handle_frame_get(scene, seq), strip_ctx->strip_content_top); immEnd(); GPU_blend(GPU_BLEND_NONE); + immUnbindProgram(); } -static void draw_seq_background(Scene *scene, - Sequence *seq, - uint pos, - float x1, - float x2, - float y1, - float y2, - bool is_single_image, - bool show_strip_color_tag) +static void draw_strip_background(TimelineDrawContext *timeline_ctx, StripDrawContext *strip_ctx) { - Editing *ed = SEQ_editing_get(scene); - ListBase *channels = SEQ_channels_displayed_get(ed); - uchar col[4]; + Scene *scene = timeline_ctx->scene; + ListBase *channels = timeline_ctx->channels; + Sequence *seq = strip_ctx->seq; + + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); GPU_blend(GPU_BLEND_ALPHA); - color3ubv_from_seq(scene, seq, show_strip_color_tag, col); - + uchar col[4]; + color3ubv_from_seq(scene, seq, strip_ctx->show_strip_color_tag, col); col[3] = mute_overlap_alpha_factor_get(channels, seq); immUniformColor4ubv(col); /* Draw the main strip body. */ - if (is_single_image) { + if (strip_ctx->is_single_image) { immRectf(pos, SEQ_time_left_handle_frame_get(scene, seq), - y1, + strip_ctx->bottom, SEQ_time_right_handle_frame_get(scene, seq), - y2); + strip_ctx->top); } else { - immRectf(pos, x1, y1, x2, y2); + immRectf( + pos, strip_ctx->content_start, strip_ctx->bottom, strip_ctx->content_end, strip_ctx->top); } /* Draw background for hold still regions. */ - if (!is_single_image) { + if (!strip_ctx->is_single_image) { UI_GetColorPtrShade3ubv(col, col, -35); immUniformColor4ubv(col); if (SEQ_time_has_left_still_frames(scene, seq)) { float left_handle_frame = SEQ_time_left_handle_frame_get(scene, seq); const float content_start = SEQ_time_start_frame_get(seq); - immRectf(pos, left_handle_frame, y1, content_start, y2); + immRectf(pos, left_handle_frame, strip_ctx->bottom, content_start, strip_ctx->top); } if (SEQ_time_has_right_still_frames(scene, seq)) { float right_handle_frame = SEQ_time_right_handle_frame_get(scene, seq); const float content_end = SEQ_time_content_end_frame_get(scene, seq); - immRectf(pos, content_end, y1, right_handle_frame, y2); + immRectf(pos, content_end, strip_ctx->bottom, right_handle_frame, strip_ctx->top); } } GPU_blend(GPU_BLEND_NONE); + immUnbindProgram(); } typedef enum { @@ -1085,20 +1290,18 @@ typedef enum { STRIP_TRANSITION_OUT, } TransitionType; -static void draw_seq_transition_strip_half(const Scene *scene, - const Sequence *transition_seq, - const float x1, - const float x2, - const float y1, - const float y2, - const int timeline_overlay_flags, +static void draw_seq_transition_strip_half(TimelineDrawContext *timeline_ctx, + StripDrawContext *strip_ctx, const TransitionType transition_type) { - Editing *ed = SEQ_editing_get(scene); + + const int timeline_overlay_flags = timeline_ctx->sseq->timeline_overlay.flag; + + Editing *ed = SEQ_editing_get(timeline_ctx->scene); const ListBase *channels = SEQ_channels_displayed_get(ed); - const Sequence *seq1 = transition_seq->seq1; - const Sequence *seq2 = transition_seq->seq2; + const Sequence *seq1 = strip_ctx->seq->seq1; + const Sequence *seq2 = strip_ctx->seq->seq2; const Sequence *target_seq = (transition_type == STRIP_TRANSITION_IN) ? seq1 : seq2; const bool show_strip_color_tag = (timeline_overlay_flags & SEQ_TIMELINE_SHOW_STRIP_COLOR_TAG); @@ -1110,7 +1313,7 @@ static void draw_seq_transition_strip_half(const Scene *scene, } else { uchar ucol[3]; - color3ubv_from_seq(scene, target_seq, show_strip_color_tag, ucol); + color3ubv_from_seq(timeline_ctx->scene, target_seq, show_strip_color_tag, ucol); /* If the transition inputs are of the same type, draw the right side slightly darker. */ if ((seq1->type == seq2->type) && (transition_type == STRIP_TRANSITION_OUT)) { UI_GetColorPtrShade3ubv(ucol, ucol, -15); @@ -1118,7 +1321,7 @@ static void draw_seq_transition_strip_half(const Scene *scene, rgb_uchar_to_float(col, ucol); } - col[3] = mute_overlap_alpha_factor_get(channels, transition_seq) / 255.0f; + col[3] = mute_overlap_alpha_factor_get(channels, strip_ctx->seq) / 255.0f; GPU_blend(GPU_BLEND_ALPHA); @@ -1131,14 +1334,14 @@ static void draw_seq_transition_strip_half(const Scene *scene, float vert_pos[3][2]; if (transition_type == STRIP_TRANSITION_IN) { - copy_v2_fl2(vert_pos[0], x1, y1); - copy_v2_fl2(vert_pos[1], x1, y2); - copy_v2_fl2(vert_pos[2], x2, y1); + copy_v2_fl2(vert_pos[0], strip_ctx->content_start, strip_ctx->bottom); + copy_v2_fl2(vert_pos[1], strip_ctx->content_start, strip_ctx->strip_content_top); + copy_v2_fl2(vert_pos[2], strip_ctx->content_end, strip_ctx->bottom); } else { - copy_v2_fl2(vert_pos[0], x1, y2); - copy_v2_fl2(vert_pos[1], x2, y2); - copy_v2_fl2(vert_pos[2], x2, y1); + copy_v2_fl2(vert_pos[0], strip_ctx->content_start, strip_ctx->strip_content_top); + copy_v2_fl2(vert_pos[1], strip_ctx->content_end, strip_ctx->strip_content_top); + copy_v2_fl2(vert_pos[2], strip_ctx->content_end, strip_ctx->bottom); } immBegin(GPU_PRIM_TRIS, 3); @@ -1152,22 +1355,25 @@ static void draw_seq_transition_strip_half(const Scene *scene, GPU_blend(GPU_BLEND_NONE); } -static void draw_seq_transition_strip(const Scene *scene, - const Sequence *seq, - const float x1, - const float x2, - const float y1, - const float y2, - const int timeline_overlay_flags) +static void draw_seq_transition_strip(TimelineDrawContext *timeline_ctx, + StripDrawContext *strip_ctx) { - draw_seq_transition_strip_half( - scene, seq, x1, x2, y1, y2, timeline_overlay_flags, STRIP_TRANSITION_IN); - draw_seq_transition_strip_half( - scene, seq, x1, x2, y1, y2, timeline_overlay_flags, STRIP_TRANSITION_OUT); + if (!strip_ctx->can_draw_strip_content || (timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) == 0 || + !ELEM(strip_ctx->seq->type, SEQ_TYPE_CROSS, SEQ_TYPE_GAMCROSS, SEQ_TYPE_WIPE)) + { + return; + } + + draw_seq_transition_strip_half(timeline_ctx, strip_ctx, STRIP_TRANSITION_IN); + draw_seq_transition_strip_half(timeline_ctx, strip_ctx, STRIP_TRANSITION_OUT); } -static void draw_seq_locked(float x1, float y1, float x2, float y2) +static void draw_seq_locked(TimelineDrawContext *timeline_ctx, StripDrawContext *strip_ctx) { + if (!SEQ_transform_is_locked(timeline_ctx->channels, strip_ctx->seq)) { + return; + } + GPU_blend(GPU_BLEND_ALPHA); uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); @@ -1178,40 +1384,35 @@ static void draw_seq_locked(float x1, float y1, float x2, float y2) immUniform1i("size1", 8); immUniform1i("size2", 4); - immRectf(pos, x1, y1, x2, y2); + immRectf( + pos, strip_ctx->left_handle, strip_ctx->bottom, strip_ctx->right_handle, strip_ctx->top); immUnbindProgram(); GPU_blend(GPU_BLEND_NONE); } -static void draw_seq_invalid(float x1, float x2, float y2, float text_margin_y) +static void draw_seq_invalid(StripDrawContext *strip_ctx) { + if (SEQ_sequence_has_source(strip_ctx->seq)) { + return; + } + GPU_blend(GPU_BLEND_ALPHA); uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); immUniformColor4f(1.0f, 0.0f, 0.0f, 0.9f); - immRectf(pos, x1, y2, x2, text_margin_y); + immRectf(pos, + strip_ctx->left_handle, + strip_ctx->top, + strip_ctx->right_handle, + strip_ctx->strip_content_top); immUnbindProgram(); GPU_blend(GPU_BLEND_NONE); } -/* For text on the strip. */ -static void calculate_seq_text_offsets( - const Scene *scene, View2D *v2d, Sequence *seq, float *x1, float *x2, float pixelx) -{ - const float handsize_clamped = sequence_handle_size_get_clamped(scene, seq, pixelx); - float text_margin = 2.0f * handsize_clamped; - - *x1 += text_margin; - *x2 -= text_margin; - - CLAMP(*x1, v2d->cur.xmin + text_margin, v2d->cur.xmax); - CLAMP(*x2, v2d->cur.xmin + text_margin, v2d->cur.xmax); -} - static void fcurve_batch_add_verts(GPUVertBuf *vbo, float y1, float y2, @@ -1235,25 +1436,32 @@ static void fcurve_batch_add_verts(GPUVertBuf *vbo, * - Volume for sound strips. * - Opacity for the other types. */ -static void draw_seq_fcurve_overlay( - Scene *scene, View2D *v2d, Sequence *seq, float x1, float y1, float x2, float y2, float pixelx) +static void draw_seq_fcurve_overlay(TimelineDrawContext *timeline_ctx, StripDrawContext *strip_ctx) { - FCurve *fcu; + if (!strip_ctx->can_draw_strip_content || (timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) == 0 || + (timeline_ctx->sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_FCURVES) == 0) + { + return; + } - if (seq->type == SEQ_TYPE_SOUND_RAM) { - fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "volume", 0, nullptr); + Scene *scene = timeline_ctx->scene; + + FCurve *fcu; + if (strip_ctx->seq->type == SEQ_TYPE_SOUND_RAM) { + fcu = id_data_find_fcurve(&scene->id, strip_ctx->seq, &RNA_Sequence, "volume", 0, nullptr); } else { - fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "blend_alpha", 0, nullptr); + fcu = id_data_find_fcurve( + &scene->id, strip_ctx->seq, &RNA_Sequence, "blend_alpha", 0, nullptr); } if (fcu && !BKE_fcurve_is_empty(fcu)) { /* Clamp curve evaluation to the editor's borders. */ - int eval_start = max_ff(x1, v2d->cur.xmin); - int eval_end = min_ff(x2, v2d->cur.xmax + 1); + int eval_start = max_ff(strip_ctx->left_handle, timeline_ctx->v2d->cur.xmin); + int eval_end = min_ff(strip_ctx->right_handle, timeline_ctx->v2d->cur.xmax + 1); - int eval_step = max_ii(1, floor(pixelx)); + int eval_step = max_ii(1, floor(timeline_ctx->pixelx)); if (eval_start >= eval_end) { return; @@ -1267,7 +1475,7 @@ static void draw_seq_fcurve_overlay( GPU_vertbuf_data_alloc(vbo, max_verts); uint vert_count = 0; - const float y_height = y2 - y1; + const float y_height = strip_ctx->top - strip_ctx->bottom; float curve_val; float prev_val = INT_MIN; bool skip = false; @@ -1285,12 +1493,23 @@ static void draw_seq_fcurve_overlay( /* If some frames were skipped above, we need to close the shape. */ if (skip) { - fcurve_batch_add_verts( - vbo, y1, y2, y_height, timeline_frame - eval_step, prev_val, &vert_count); + fcurve_batch_add_verts(vbo, + strip_ctx->bottom, + strip_ctx->top, + y_height, + timeline_frame - eval_step, + prev_val, + &vert_count); skip = false; } - fcurve_batch_add_verts(vbo, y1, y2, y_height, timeline_frame, curve_val, &vert_count); + fcurve_batch_add_verts(vbo, + strip_ctx->bottom, + strip_ctx->top, + y_height, + timeline_frame, + curve_val, + &vert_count); prev_val = curve_val; } @@ -1310,187 +1529,29 @@ static void draw_seq_fcurve_overlay( } /* Draw visible strips. Bounds check are already made. */ -static void draw_seq_strip(const bContext *C, - SpaceSeq *sseq, - Scene *scene, - ARegion *region, - Sequence *seq, - float pixelx, - bool seq_active) +static void draw_seq_strip(TimelineDrawContext *timeline_ctx, StripDrawContext *strip_ctx) { - Editing *ed = SEQ_editing_get(CTX_data_scene(C)); - ListBase *channels = SEQ_channels_displayed_get(ed); - - View2D *v2d = ®ion->v2d; - float x1, x2, y1, y2; - const float handsize_clamped = sequence_handle_size_get_clamped(scene, seq, pixelx); - float pixely = BLI_rctf_size_y(&v2d->cur) / BLI_rcti_size_y(&v2d->mask); - - /* Check if we are doing "solo preview". */ - bool is_single_image = char(SEQ_transform_single_image_check(seq)); - - /* Use the seq->color_tag to display the tag color. */ - const bool show_strip_color_tag = (sseq->timeline_overlay.flag & - SEQ_TIMELINE_SHOW_STRIP_COLOR_TAG); - - /* Draw strip body. */ - x1 = SEQ_time_has_left_still_frames(scene, seq) ? SEQ_time_start_frame_get(seq) : - SEQ_time_left_handle_frame_get(scene, seq); - y1 = seq->machine + SEQ_STRIP_OFSBOTTOM; - x2 = SEQ_time_has_right_still_frames(scene, seq) ? SEQ_time_content_end_frame_get(scene, seq) : - SEQ_time_right_handle_frame_get(scene, seq); - y2 = seq->machine + SEQ_STRIP_OFSTOP; - - /* Limit body to strip bounds. Meta strip can end up with content outside of strip range. */ - x1 = min_ff(x1, SEQ_time_right_handle_frame_get(scene, seq)); - x2 = max_ff(x2, SEQ_time_left_handle_frame_get(scene, seq)); - - float text_margin_y; - /* Whether there is enough space for the strip preview. */ - const bool draw_strip_preview = ((y2 - y1) / pixely) > 20 * UI_SCALE_FAC; - /* If there is not enough vertical space, don't draw any previews nor the title. */ - const bool strip_content_none = (y2 - y1) < 8 * pixely * UI_SCALE_FAC; - /* Only a single vertical element is drawn on the strip: the waveform in the case of - * sound strips, or the strip title for most other strip types. */ - bool strip_content_single; - - if ((sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_NAME) || - (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_SOURCE) || - (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_DURATION)) - { - - /* Calculate height needed for drawing text on strip. */ - text_margin_y = y2 - min_ff(0.40f, 20 * UI_SCALE_FAC * pixely); - - strip_content_single = !draw_strip_preview; - } - else { - text_margin_y = y2; - strip_content_single = true; - } - /* When a text overlay is enabled and there is space for both the text and the strip content, - * draw below the text. */ - /* When text is disabled or there is space for only one or the other, use entire strip area. */ - const float strip_preview_y2 = strip_content_single ? y2 : text_margin_y; - - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - - draw_seq_background(scene, seq, pos, x1, x2, y1, y2, is_single_image, show_strip_color_tag); - - /* Draw a color band inside color strip. */ - if ((sseq->flag & SEQ_SHOW_OVERLAY) && (seq->type == SEQ_TYPE_COLOR)) { - draw_color_strip_band(scene, channels, seq, pos, strip_preview_y2, y1); - } - - /* Draw strip offsets when flag is enabled or during "solo preview". */ - if (sseq->flag & SEQ_SHOW_OVERLAY) { - if (!is_single_image && pixely > 0) { - if ((sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_OFFSETS) || - (seq == special_seq_update)) { - draw_sequence_extensions_overlay(scene, seq, pos, pixely, show_strip_color_tag); - } - } - } - immUnbindProgram(); - - if (draw_strip_preview && (sseq->flag & SEQ_SHOW_OVERLAY) && - ELEM(seq->type, SEQ_TYPE_CROSS, SEQ_TYPE_GAMCROSS, SEQ_TYPE_WIPE)) - { - draw_seq_transition_strip( - scene, seq, x1, x2, y1, strip_preview_y2, sseq->timeline_overlay.flag); - } - - x1 = SEQ_time_left_handle_frame_get(scene, seq); - x2 = SEQ_time_right_handle_frame_get(scene, seq); - - if (draw_strip_preview && (sseq->flag & SEQ_SHOW_OVERLAY)) { - if ((seq->type == SEQ_TYPE_META) || - ((seq->type == SEQ_TYPE_SCENE) && (seq->flag & SEQ_SCENE_STRIPS))) - { - drawmeta_contents(scene, seq, x1, y1, x2, strip_preview_y2, show_strip_color_tag); - } - } - - if ((sseq->flag & SEQ_SHOW_OVERLAY) && - (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_THUMBNAILS) && - ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE)) - { - draw_seq_strip_thumbnail(v2d, C, scene, seq, y1, strip_preview_y2, pixelx, pixely); - } - - if (draw_strip_preview && (sseq->flag & SEQ_SHOW_OVERLAY) && - (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_FCURVES)) - { - draw_seq_fcurve_overlay(scene, v2d, seq, x1, y1, x2, strip_preview_y2, pixelx); - } - - /* Draw sound strip waveform. */ - if (seq_draw_waveforms_poll(C, sseq, seq) && !strip_content_none) { - draw_seq_waveform_overlay( - C, region, seq, x1, strip_content_single ? y1 : y1 + 0.05f, x2, strip_preview_y2); - } - /* Draw locked state. */ - if (SEQ_transform_is_locked(channels, seq)) { - draw_seq_locked(x1, y1, x2, y2); - } - - /* Draw Red line on the top of invalid strip (Missing media). */ - if (!SEQ_sequence_has_source(seq)) { - draw_seq_invalid(x1, x2, y2, text_margin_y); - } - - pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - - if (!SEQ_transform_is_locked(channels, seq)) { - draw_seq_handle(scene, - v2d, - seq, - handsize_clamped, - SEQ_LEFTHANDLE, - pos, - seq_active, - pixelx, - draw_strip_preview); - draw_seq_handle(scene, - v2d, - seq, - handsize_clamped, - SEQ_RIGHTHANDLE, - pos, - seq_active, - pixelx, - draw_strip_preview); - } - - draw_seq_outline(scene, seq, pos, x1, x2, y1, y2, pixelx, pixely, seq_active); - - immUnbindProgram(); - - /* If a waveform or a color strip is drawn, - * avoid drawing text when there is not enough vertical space. */ - if (strip_content_single && - (seq_draw_waveforms_poll(C, sseq, seq) || seq->type == SEQ_TYPE_COLOR)) { - return; - } - - if (sseq->flag & SEQ_SHOW_OVERLAY) { - /* Draw text only if there is enough horizontal or vertical space. */ - if (((x2 - x1) > 32 * pixelx * UI_SCALE_FAC) && !strip_content_none) { - calculate_seq_text_offsets(scene, v2d, seq, &x1, &x2, pixelx); - /* Depending on the vertical space, draw text on top or in the center of strip. */ - draw_seq_text_overlay(scene, - v2d, - seq, - sseq, - x1, - x2, - strip_content_single ? y1 : text_margin_y, - y2, - seq_active); - } - } + draw_strip_background(timeline_ctx, strip_ctx); + draw_strip_color_band(timeline_ctx, strip_ctx); + draw_strip_offsets(timeline_ctx, strip_ctx); + draw_seq_transition_strip(timeline_ctx, strip_ctx); + drawmeta_contents(timeline_ctx, strip_ctx); + draw_seq_strip_thumbnail(timeline_ctx->v2d, + timeline_ctx->C, + timeline_ctx->scene, + strip_ctx->seq, + strip_ctx->bottom, + strip_ctx->strip_content_top, + timeline_ctx->pixelx, + timeline_ctx->pixely); + draw_seq_fcurve_overlay(timeline_ctx, strip_ctx); + draw_seq_waveform_overlay(timeline_ctx, strip_ctx); + draw_seq_locked(timeline_ctx, strip_ctx); + draw_seq_invalid(strip_ctx); /* Draw Red line on the top of invalid strip (Missing media). */ + draw_seq_handle(timeline_ctx, strip_ctx, SEQ_LEFTHANDLE); + draw_seq_handle(timeline_ctx, strip_ctx, SEQ_RIGHTHANDLE); + draw_seq_outline(timeline_ctx, strip_ctx); + draw_seq_text_overlay(timeline_ctx, strip_ctx); } static void draw_effect_inputs_highlight(const Scene *scene, Sequence *seq) @@ -1536,8 +1597,10 @@ static void seq_prefetch_wm_notify(const bContext *C, Scene *scene) } } -static void draw_seq_timeline_channels(View2D *v2d) +static void draw_seq_timeline_channels(TimelineDrawContext *ctx) { + View2D *v2d = ctx->v2d; + UI_view2d_view_ortho(v2d); uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); GPU_blend(GPU_BLEND_ALPHA); @@ -1556,14 +1619,19 @@ static void draw_seq_timeline_channels(View2D *v2d) immUnbindProgram(); } -static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region) +static void draw_seq_strips(TimelineDrawContext *timeline_ctx) { + if (timeline_ctx->ed == nullptr) { + return; + } + + const bContext *C = timeline_ctx->C; + Editing *ed = timeline_ctx->ed; + ARegion *region = timeline_ctx->region; Scene *scene = CTX_data_scene(C); View2D *v2d = ®ion->v2d; - SpaceSeq *sseq = CTX_wm_space_seq(C); Sequence *last_seq = SEQ_select_active_get(scene); int sel = 0, j; - float pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask); /* Loop through twice, first unselected, then selected. */ for (j = 0; j < 2; j++) { @@ -1594,7 +1662,8 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region) } /* Strip passed all tests, draw it now. */ - draw_seq_strip(C, sseq, scene, region, seq, pixelx, seq == last_seq ? true : false); + StripDrawContext strip_ctx = strip_draw_context_get(timeline_ctx, seq); + draw_seq_strip(timeline_ctx, &strip_ctx); } /* Draw selected next time round. */ @@ -1604,7 +1673,8 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region) /* When selected draw the last selected (active) strip last, * removes some overlapping error. */ if (last_seq && (last_seq->flag & SELECT)) { - draw_seq_strip(C, sseq, scene, region, last_seq, pixelx, true); + StripDrawContext strip_ctx = strip_draw_context_get(timeline_ctx, last_seq); + draw_seq_strip(timeline_ctx, &strip_ctx); /* When active strip is an effect, highlight its inputs. */ if (SEQ_effect_get_num_inputs(last_seq->type) > 0) { @@ -1647,10 +1717,14 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region) GPU_blend(GPU_BLEND_NONE); } + + UI_view2d_text_cache_draw(region); } -static void seq_draw_sfra_efra(const Scene *scene, View2D *v2d) +static void draw_timeline_sfra_efra(TimelineDrawContext *ctx) { + const Scene *scene = ctx->scene; + const View2D *v2d = ctx->v2d; const Editing *ed = SEQ_editing_get(scene); const int frame_sta = scene->r.sfra; const int frame_end = scene->r.efra + 1; @@ -1973,78 +2047,88 @@ static void draw_overlap_frame_indicator(const Scene *scene, const View2D *v2d) immUnbindProgram(); } +static void draw_timeline_grid(TimelineDrawContext *ctx) +{ + if ((ctx->sseq->flag & SEQ_SHOW_OVERLAY) == 0 || + (ctx->sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_GRID) == 0) + { + return; + } + + U.v2d_min_gridsize *= 3; + UI_view2d_draw_lines_x__discrete_frames_or_seconds( + ctx->v2d, ctx->scene, (ctx->sseq->flag & SEQ_DRAWFRAMES) == 0, false); + U.v2d_min_gridsize /= 3; +} + +static void draw_timeline_backdrop(TimelineDrawContext *ctx) +{ + if (ctx->sseq->view = !SEQ_VIEW_SEQUENCE || (ctx->sseq->draw_flag & SEQ_DRAW_BACKDROP) == 0) { + return; + } + + int preview_frame = ctx->scene->r.cfra; + if (sequencer_draw_get_transform_preview(ctx->sseq, ctx->scene)) { + preview_frame = sequencer_draw_get_transform_preview_frame(ctx->scene); + } + + sequencer_draw_preview( + ctx->C, ctx->scene, ctx->region, ctx->sseq, preview_frame, 0, false, true); + UI_view2d_view_ortho(ctx->v2d); +} + +static void draw_timeline_markers(TimelineDrawContext *ctx) +{ + if ((ctx->sseq->flag & SEQ_SHOW_MARKERS) == 0) { + return; + } + + UI_view2d_view_orthoSpecial(ctx->region, ctx->v2d, true); + ED_markers_draw(ctx->C, DRAW_MARKERS_MARGIN); +} + +static void draw_timeline_gizmos(TimelineDrawContext *ctx) +{ + if ((ctx->sseq->gizmo_flag & SEQ_GIZMO_HIDE) != 0) { + return; + } + + WM_gizmomap_draw(ctx->region->gizmo_map, ctx->C, WM_GIZMOMAP_DRAWSTEP_2D); +} + +static void draw_timeline_pre_view_callbacks(TimelineDrawContext *ctx) +{ + GPU_framebuffer_bind_no_srgb(ctx->framebuffer_overlay); + GPU_depth_test(GPU_DEPTH_NONE); + GPU_framebuffer_bind(ctx->framebuffer_overlay); + ED_region_draw_cb_draw(ctx->C, ctx->region, REGION_DRAW_PRE_VIEW); + GPU_framebuffer_bind_no_srgb(ctx->framebuffer_overlay); +} + +static void draw_timeline_post_view_callbacks(TimelineDrawContext *ctx) +{ + GPU_framebuffer_bind(ctx->framebuffer_overlay); + ED_region_draw_cb_draw(ctx->C, ctx->region, REGION_DRAW_POST_VIEW); + GPU_framebuffer_bind_no_srgb(ctx->framebuffer_overlay); +} + void draw_timeline_seq(const bContext *C, ARegion *region) { - Scene *scene = CTX_data_scene(C); - Editing *ed = SEQ_editing_get(scene); - SpaceSeq *sseq = CTX_wm_space_seq(C); - View2D *v2d = ®ion->v2d; - - seq_prefetch_wm_notify(C, scene); - - GPUViewport *viewport = WM_draw_region_get_viewport(region); - GPUFrameBuffer *framebuffer_overlay = GPU_viewport_framebuffer_overlay_get(viewport); - GPU_framebuffer_bind_no_srgb(framebuffer_overlay); - GPU_depth_test(GPU_DEPTH_NONE); - + TimelineDrawContext ctx = timeline_draw_context_get(C); + draw_timeline_pre_view_callbacks(&ctx); UI_ThemeClearColor(TH_BACK); + draw_seq_timeline_channels(&ctx); + draw_timeline_grid(&ctx); + draw_timeline_backdrop(&ctx); + draw_timeline_sfra_efra(&ctx); + draw_seq_strips(&ctx); + draw_timeline_markers(&ctx); + ANIM_draw_previewrange(C, ctx.v2d, 1); + draw_timeline_gizmos(&ctx); + draw_timeline_post_view_callbacks(&ctx); + ED_time_scrub_draw(region, ctx.scene, !(ctx.sseq->flag & SEQ_DRAWFRAMES), true); - UI_view2d_view_ortho(v2d); - draw_seq_timeline_channels(v2d); - - if ((sseq->flag & SEQ_SHOW_OVERLAY) && (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_GRID)) { - U.v2d_min_gridsize *= 3; - UI_view2d_draw_lines_x__discrete_frames_or_seconds( - v2d, scene, (sseq->flag & SEQ_DRAWFRAMES) == 0, false); - U.v2d_min_gridsize /= 3; - } - - /* Only draw backdrop in timeline view. */ - if (sseq->view == SEQ_VIEW_SEQUENCE && sseq->draw_flag & SEQ_DRAW_BACKDROP) { - int preview_frame = scene->r.cfra; - if (sequencer_draw_get_transform_preview(sseq, scene)) { - preview_frame = sequencer_draw_get_transform_preview_frame(scene); - } - - sequencer_draw_preview(C, scene, region, sseq, preview_frame, 0, false, true); - UI_view2d_view_ortho(v2d); - } - - /* Draw attached callbacks. */ - GPU_framebuffer_bind(framebuffer_overlay); - ED_region_draw_cb_draw(C, region, REGION_DRAW_PRE_VIEW); - GPU_framebuffer_bind_no_srgb(framebuffer_overlay); - - seq_draw_sfra_efra(scene, v2d); - - if (ed) { - draw_seq_strips(C, ed, region); - /* Draw text added in previous function. */ - UI_view2d_text_cache_draw(region); - } - - UI_view2d_view_ortho(v2d); - - UI_view2d_view_orthoSpecial(region, v2d, true); - int marker_draw_flag = DRAW_MARKERS_MARGIN; - if (sseq->flag & SEQ_SHOW_MARKERS) { - ED_markers_draw(C, marker_draw_flag); - } - - UI_view2d_view_ortho(v2d); - ANIM_draw_previewrange(C, v2d, 1); - - if ((sseq->gizmo_flag & SEQ_GIZMO_HIDE) == 0) { - WM_gizmomap_draw(region->gizmo_map, C, WM_GIZMOMAP_DRAWSTEP_2D); - } - - /* Draw registered callbacks. */ - GPU_framebuffer_bind(framebuffer_overlay); - ED_region_draw_cb_draw(C, region, REGION_DRAW_POST_VIEW); - GPU_framebuffer_bind_no_srgb(framebuffer_overlay); - - UI_view2d_view_restore(C); - ED_time_scrub_draw(region, scene, !(sseq->flag & SEQ_DRAWFRAMES), true); + seq_prefetch_wm_notify(C, ctx.scene); } void draw_timeline_seq_display(const bContext *C, ARegion *region)