Fix: Retiming keys do not respect strip drawing order

Retiming was drawn for all strips in one draw call. During strip
transformation, if strips overlap, one strip should cover the other.
But all keys were drawn on top.

Retiming drawing API was changed to draw 1 strip, so overlapped strips
can be drawn first, followed by overlapping strips.
Since retiming drawing is also layered, single draw call was split into
drawing continuity line, keys and speed text.
This commit is contained in:
Richard Antalik
2024-07-11 06:00:59 +02:00
parent b8a1e41dc2
commit d0cf4a4a8b
3 changed files with 193 additions and 211 deletions

View File

@@ -8,13 +8,20 @@
#pragma once
#include "BLI_map.hh"
#include "BLI_utility_mixins.hh"
#include "BLI_vector.hh"
#include "BLI_vector_set.hh"
#include "DNA_sequence_types.h"
#include "ED_sequencer.hh"
#include "RNA_access.hh"
#include "GPU_immediate.hh"
#include "GPU_viewport.hh"
#include "ED_sequencer.hh"
#include "sequencer_scopes.hh"
/* Internal exports only. */
@@ -80,6 +87,41 @@ struct SeqChannelDrawContext {
float scale;
};
struct StripDrawContext {
Sequence *seq;
/* Strip boundary in timeline space. Content start/end is clamped by left/right handle. */
float content_start, content_end, bottom, top;
float left_handle, right_handle; /* Position in frames. */
float strip_content_top; /* Position in timeline space without content and text overlay. */
float handle_width; /* Width of strip handle in frames. */
float strip_length;
bool can_draw_text_overlay;
bool can_draw_strip_content;
bool strip_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;
bool missing_data_block;
bool missing_media;
};
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. */
blender::Map<SeqRetimingKey *, Sequence *> retiming_selection;
SeqQuadsBatch *quads;
};
/* `sequencer_timeline_draw.cc` */
void draw_timeline_seq(const bContext *C, ARegion *region);
@@ -329,7 +371,12 @@ int sequencer_retiming_select_all_exec(bContext *C, wmOperator *op);
int sequencer_retiming_box_select_exec(bContext *C, wmOperator *op);
/* `sequencer_retiming_draw.cc` */
void sequencer_draw_retiming(const bContext *C, SeqQuadsBatch *quads);
void sequencer_retiming_draw_continuity(const TimelineDrawContext *timeline_ctx,
const StripDrawContext &strip_ctx);
void sequencer_retiming_keys_draw(const TimelineDrawContext *timeline_ctx,
const StripDrawContext &strip_ctx);
void sequencer_retiming_speed_draw(const TimelineDrawContext *timeline_ctx,
const StripDrawContext &strip_ctx);
SeqRetimingKey *try_to_realize_virtual_keys(const bContext *C, Sequence *seq, const int mval[2]);
SeqRetimingKey *retiming_mousover_key_get(const bContext *C, const int mval[2], Sequence **r_seq);
int left_fake_key_frame_get(const bContext *C, const Sequence *seq);

View File

@@ -19,7 +19,6 @@
#include "BLF_api.hh"
#include "GPU_batch.hh"
#include "GPU_immediate.hh"
#include "GPU_state.hh"
#include "WM_api.hh"
@@ -227,18 +226,36 @@ SeqRetimingKey *retiming_mousover_key_get(const bContext *C, const int mval[2],
return nullptr;
}
static bool can_draw_retiming(const TimelineDrawContext *timeline_ctx,
const StripDrawContext &strip_ctx)
{
if (timeline_ctx->ed == nullptr) {
return false;
}
if (!retiming_keys_are_visible(timeline_ctx->sseq)) {
return false;
}
if (!SEQ_retiming_is_allowed(strip_ctx.seq)) {
return false;
}
return true;
}
/* -------------------------------------------------------------------- */
/** \name Retiming Key
* \{ */
static void retime_key_draw(const bContext *C,
const Sequence *seq,
static void retime_key_draw(const TimelineDrawContext *timeline_ctx,
const StripDrawContext &strip_ctx,
const SeqRetimingKey *key,
const KeyframeShaderBindings &sh_bindings,
const blender::Map<SeqRetimingKey *, Sequence *> &selection)
const KeyframeShaderBindings &sh_bindings)
{
const Scene *scene = CTX_data_scene(C);
const View2D *v2d = UI_view2d_fromcontext(C);
const Scene *scene = timeline_ctx->scene;
const View2D *v2d = timeline_ctx->v2d;
Sequence *seq = strip_ctx.seq;
const float key_x = key_x_get(scene, seq, key);
const rctf strip_box = strip_box_get(scene, v2d, seq);
@@ -254,17 +271,14 @@ static void retime_key_draw(const bContext *C,
key_type = BEZT_KEYTYPE_MOVEHOLD;
}
const bool is_selected = selection.contains(const_cast<SeqRetimingKey *>(key));
const bool is_selected = timeline_ctx->retiming_selection.contains(
const_cast<SeqRetimingKey *>(key));
const int size = KEY_SIZE;
const float bottom = KEY_CENTER;
/* Ensure, that key is always inside of strip. */
const float right_pos_max = UI_view2d_view_to_region_x(
v2d, SEQ_time_right_handle_frame_get(scene, seq)) -
(size / 2);
const float left_pos_min = UI_view2d_view_to_region_x(
v2d, SEQ_time_left_handle_frame_get(scene, seq)) +
(size / 2);
const float right_pos_max = UI_view2d_view_to_region_x(v2d, strip_ctx.right_handle) - (size / 2);
const float left_pos_min = UI_view2d_view_to_region_x(v2d, strip_ctx.left_handle) + (size / 2);
float key_position = UI_view2d_view_to_region_x(v2d, key_x);
CLAMP(key_position, left_pos_min, right_pos_max);
const float alpha = SEQ_retiming_data_is_editable(seq) ? 1.0f : 0.3f;
@@ -281,134 +295,115 @@ static void retime_key_draw(const bContext *C,
0);
}
static void draw_continuity(const bContext *C,
const Sequence *seq,
const SeqRetimingKey *key,
const blender::Map<SeqRetimingKey *, Sequence *> &selection,
SeqQuadsBatch *quads)
void sequencer_retiming_draw_continuity(const TimelineDrawContext *timeline_ctx,
const StripDrawContext &strip_ctx)
{
const View2D *v2d = UI_view2d_fromcontext(C);
const Scene *scene = CTX_data_scene(C);
if (key_x_get(scene, seq, key) == SEQ_time_left_handle_frame_get(scene, seq) ||
key->strip_frame_index == 0)
{
if (!can_draw_retiming(timeline_ctx, strip_ctx)) {
return;
}
const float left_handle_position = UI_view2d_view_to_region_x(
v2d, SEQ_time_left_handle_frame_get(scene, seq));
const float right_handle_position = UI_view2d_view_to_region_x(
v2d, SEQ_time_right_handle_frame_get(scene, seq));
wmOrtho2_region_pixelspace(timeline_ctx->region);
float key_position = UI_view2d_view_to_region_x(v2d, key_x_get(scene, seq, key));
float prev_key_position = UI_view2d_view_to_region_x(v2d, key_x_get(scene, seq, key - 1));
prev_key_position = max_ff(prev_key_position, left_handle_position);
key_position = min_ff(key_position, right_handle_position);
const Sequence *seq = strip_ctx.seq;
const View2D *v2d = timeline_ctx->v2d;
const Scene *scene = timeline_ctx->scene;
const float left_handle_position = UI_view2d_view_to_region_x(v2d, strip_ctx.left_handle);
const float right_handle_position = UI_view2d_view_to_region_x(v2d, strip_ctx.right_handle);
const int size = KEY_SIZE;
const float y_center = KEY_CENTER;
for (const SeqRetimingKey &key : SEQ_retiming_keys_get(seq)) {
if (key_x_get(scene, seq, &key) == strip_ctx.left_handle || key.strip_frame_index == 0) {
continue;
}
const float width_fac = 0.5f;
const float bottom = y_center - size * width_fac;
const float top = y_center + size * width_fac;
float key_position = UI_view2d_view_to_region_x(v2d, key_x_get(scene, seq, &key));
float prev_key_position = UI_view2d_view_to_region_x(v2d, key_x_get(scene, seq, &key - 1));
prev_key_position = max_ff(prev_key_position, left_handle_position);
key_position = min_ff(key_position, right_handle_position);
uchar color[4];
if (SEQ_retiming_data_is_editable(seq) &&
(selection.contains(const_cast<SeqRetimingKey *>(key)) ||
selection.contains(const_cast<SeqRetimingKey *>(key - 1))))
{
color[0] = 166;
color[1] = 127;
color[2] = 51;
color[3] = 255;
const int size = KEY_SIZE;
const float y_center = KEY_CENTER;
const float width_fac = 0.5f;
const float bottom = y_center - size * width_fac;
const float top = y_center + size * width_fac;
uchar color[4];
if (SEQ_retiming_data_is_editable(seq) &&
(timeline_ctx->retiming_selection.contains(const_cast<SeqRetimingKey *>(&key)) ||
timeline_ctx->retiming_selection.contains(const_cast<SeqRetimingKey *>(&key - 1))))
{
color[0] = 166;
color[1] = 127;
color[2] = 51;
color[3] = 255;
}
else {
color[0] = 0;
color[1] = 0;
color[2] = 0;
color[3] = 25;
}
timeline_ctx->quads->add_quad(prev_key_position, bottom, key_position, top, color);
}
else {
color[0] = 0;
color[1] = 0;
color[2] = 0;
color[3] = 25;
}
quads->add_quad(prev_key_position, bottom, key_position, top, color);
}
static SeqRetimingKey retiming_key_init(const Scene *scene,
const Sequence *seq,
int timeline_frame)
{
SeqRetimingKey fake_key;
fake_key.strip_frame_index = (timeline_frame - SEQ_time_start_frame_get(seq)) *
SEQ_time_media_playback_rate_factor_get(scene, seq);
fake_key.flag = 0;
return fake_key;
}
/* If there are no keys, draw fake keys and create real key when they are selected. */
/* TODO: would be nice to draw continuity between fake keys. */
static bool fake_keys_draw(const bContext *C,
Sequence *seq,
const KeyframeShaderBindings &sh_bindings,
const blender::Map<SeqRetimingKey *, Sequence *> &selection)
static bool fake_keys_draw(const TimelineDrawContext *timeline_ctx,
const StripDrawContext &strip_ctx,
const KeyframeShaderBindings &sh_bindings)
{
const Sequence *seq = strip_ctx.seq;
const Scene *scene = timeline_ctx->scene;
if (!SEQ_retiming_is_active(seq) && !SEQ_retiming_data_is_editable(seq)) {
return false;
}
const Scene *scene = CTX_data_scene(C);
const int left_key_frame = left_fake_key_frame_get(C, seq);
int right_key_frame = right_fake_key_frame_get(C, seq);
const int left_key_frame = left_fake_key_frame_get(timeline_ctx->C, seq);
if (SEQ_retiming_key_get_by_timeline_frame(scene, seq, left_key_frame) == nullptr) {
SeqRetimingKey fake_key;
fake_key.strip_frame_index = (left_key_frame - SEQ_time_start_frame_get(seq)) *
SEQ_time_media_playback_rate_factor_get(scene, seq);
fake_key.flag = 0;
retime_key_draw(C, seq, &fake_key, sh_bindings, selection);
SeqRetimingKey fake_key = retiming_key_init(scene, seq, left_key_frame);
retime_key_draw(timeline_ctx, strip_ctx, &fake_key, sh_bindings);
}
int right_key_frame = right_fake_key_frame_get(timeline_ctx->C, seq);
if (SEQ_retiming_key_get_by_timeline_frame(scene, seq, right_key_frame) == nullptr) {
/* `key_x_get()` compensates 1 frame offset of last key, however this can not
* be conveyed via `fake_key` alone. Therefore the same offset must be emulated. */
if (SEQ_time_right_handle_frame_get(scene, seq) >= SEQ_time_content_end_frame_get(scene, seq))
{
if (strip_ctx.right_handle >= SEQ_time_content_end_frame_get(scene, seq)) {
right_key_frame += 1;
}
SeqRetimingKey fake_key;
fake_key.strip_frame_index = (right_key_frame - SEQ_time_start_frame_get(seq)) *
SEQ_time_media_playback_rate_factor_get(scene, seq);
fake_key.flag = 0;
retime_key_draw(C, seq, &fake_key, sh_bindings, selection);
SeqRetimingKey fake_key = retiming_key_init(scene, seq, right_key_frame);
retime_key_draw(timeline_ctx, strip_ctx, &fake_key, sh_bindings);
}
return true;
}
static void retime_keys_draw(const bContext *C, SeqQuadsBatch *quads)
void sequencer_retiming_keys_draw(const TimelineDrawContext *timeline_ctx,
const StripDrawContext &strip_ctx)
{
const Scene *scene = CTX_data_scene(C);
if (scene->ed == nullptr) {
if (!can_draw_retiming(timeline_ctx, strip_ctx)) {
return;
}
if (!retiming_keys_are_visible(CTX_wm_space_seq(C))) {
return;
}
wmOrtho2_region_pixelspace(timeline_ctx->region);
/* Get the selection here once, for faster "is key selected?" lookups later. */
blender::Map<SeqRetimingKey *, Sequence *> selection = SEQ_retiming_selection_get(scene->ed);
wmOrtho2_region_pixelspace(CTX_wm_region(C));
blender::Vector<Sequence *> strips = sequencer_visible_strips_get(C);
/* Draw all continuity sections. */
GPU_blend(GPU_BLEND_ALPHA);
for (Sequence *seq : strips) {
if (!SEQ_retiming_is_allowed(seq)) {
continue;
}
for (const SeqRetimingKey &key : SEQ_retiming_keys_get(seq)) {
draw_continuity(C, seq, &key, selection, quads);
}
}
quads->draw();
/* Draw all keys. */
const View2D *v2d = UI_view2d_fromcontext(C);
const View2D *v2d = timeline_ctx->v2d;
const Sequence *seq = strip_ctx.seq;
GPUVertFormat *format = immVertexFormat();
KeyframeShaderBindings sh_bindings;
sh_bindings.pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
sh_bindings.size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
sh_bindings.color_id = GPU_vertformat_attr_add(
@@ -426,32 +421,26 @@ static void retime_keys_draw(const bContext *C, SeqQuadsBatch *quads)
int point_counter = 0;
immBeginAtMost(GPU_PRIM_POINTS, MAX_KEYS_IN_BATCH);
for (Sequence *seq : strips) {
if (!SEQ_retiming_is_allowed(seq)) {
continue;
}
if (fake_keys_draw(timeline_ctx, strip_ctx, sh_bindings)) {
point_counter += 2;
}
if (fake_keys_draw(C, seq, sh_bindings, selection)) {
point_counter += 2;
}
for (const SeqRetimingKey &key : SEQ_retiming_keys_get(seq)) {
retime_key_draw(timeline_ctx, strip_ctx, &key, sh_bindings);
point_counter++;
for (const SeqRetimingKey &key : SEQ_retiming_keys_get(seq)) {
retime_key_draw(C, seq, &key, sh_bindings, selection);
point_counter++;
/* Next key plus possible two fake keys for next sequence would need at
* most 3 points, so restart the batch if we're close to that. */
if (point_counter + 3 >= MAX_KEYS_IN_BATCH) {
immEnd();
immBeginAtMost(GPU_PRIM_POINTS, MAX_KEYS_IN_BATCH);
point_counter = 0;
}
/* Next key plus possible two fake keys for next sequence would need at
* most 3 points, so restart the batch if we're close to that. */
if (point_counter + 3 >= MAX_KEYS_IN_BATCH) {
immEnd();
immBeginAtMost(GPU_PRIM_POINTS, MAX_KEYS_IN_BATCH);
point_counter = 0;
}
}
immEnd();
GPU_program_point_size(false);
immUnbindProgram();
GPU_blend(GPU_BLEND_NONE);
}
/** \} */
@@ -480,45 +469,44 @@ static size_t label_str_get(const Sequence *seq,
r_label_str, label_str_maxncpy, "%d%%", round_fl_to_int(speed * 100.0f));
}
static bool label_rect_get(const bContext *C,
const Sequence *seq,
static bool label_rect_get(const TimelineDrawContext *timeline_ctx,
const StripDrawContext &strip_ctx,
const SeqRetimingKey *key,
const char *label_str,
const size_t label_len,
rctf *rect)
{
const Scene *scene = CTX_data_scene(C);
const bContext *C = timeline_ctx->C;
const Scene *scene = timeline_ctx->scene;
const SeqRetimingKey *next_key = key + 1;
const float width = pixels_to_view_width(C, BLF_width(BLF_default(), label_str, label_len));
const float height = pixels_to_view_height(C, BLF_height(BLF_default(), label_str, label_len));
const float xmin = max_ff(SEQ_time_left_handle_frame_get(scene, seq),
key_x_get(scene, seq, key));
const float xmax = min_ff(SEQ_time_right_handle_frame_get(scene, seq),
key_x_get(scene, seq, next_key));
const float xmin = max_ff(strip_ctx.left_handle, key_x_get(scene, strip_ctx.seq, key));
const float xmax = min_ff(strip_ctx.right_handle, key_x_get(scene, strip_ctx.seq, next_key));
rect->xmin = (xmin + xmax - width) / 2;
rect->xmax = rect->xmin + width;
rect->ymin = strip_y_rescale(seq, 0) + pixels_to_view_height(C, 5);
rect->ymin = strip_y_rescale(strip_ctx.seq, 0) + pixels_to_view_height(C, 5);
rect->ymax = rect->ymin + height;
return width < xmax - xmin - pixels_to_view_width(C, KEY_SIZE);
}
static void retime_speed_text_draw(const bContext *C,
const Sequence *seq,
static void retime_speed_text_draw(const TimelineDrawContext *timeline_ctx,
const StripDrawContext &strip_ctx,
const SeqRetimingKey *key)
{
const Sequence *seq = strip_ctx.seq;
const Scene *scene = timeline_ctx->scene;
if (SEQ_retiming_is_last_key(seq, key)) {
return;
}
const Scene *scene = CTX_data_scene(C);
const int start_frame = SEQ_time_left_handle_frame_get(scene, seq);
const int end_frame = SEQ_time_right_handle_frame_get(scene, seq);
const SeqRetimingKey *next_key = key + 1;
if (key_x_get(scene, seq, next_key) < start_frame || key_x_get(scene, seq, key) > end_frame) {
if (key_x_get(scene, seq, next_key) < strip_ctx.left_handle ||
key_x_get(scene, seq, key) > strip_ctx.right_handle)
{
return; /* Label out of strip bounds. */
}
@@ -526,7 +514,7 @@ static void retime_speed_text_draw(const bContext *C,
rctf label_rect;
size_t label_len = label_str_get(seq, key, label_str, sizeof(label_str));
if (!label_rect_get(C, seq, key, label_str, label_len, &label_rect)) {
if (!label_rect_get(timeline_ctx, strip_ctx, key, label_str, label_len, &label_rect)) {
return; /* Not enough space to draw the label. */
}
@@ -537,44 +525,21 @@ static void retime_speed_text_draw(const bContext *C,
}
UI_view2d_text_cache_add(
UI_view2d_fromcontext(C), label_rect.xmin, label_rect.ymin, label_str, label_len, col);
timeline_ctx->v2d, label_rect.xmin, label_rect.ymin, label_str, label_len, col);
}
static void retime_speed_draw(const bContext *C)
void sequencer_retiming_speed_draw(const TimelineDrawContext *timeline_ctx,
const StripDrawContext &strip_ctx)
{
const Scene *scene = CTX_data_scene(C);
if (scene->ed == nullptr) {
if (!can_draw_retiming(timeline_ctx, strip_ctx)) {
return;
}
if (!retiming_keys_are_visible(CTX_wm_space_seq(C))) {
return;
for (const SeqRetimingKey &key : SEQ_retiming_keys_get(strip_ctx.seq)) {
retime_speed_text_draw(timeline_ctx, strip_ctx, &key);
}
const View2D *v2d = UI_view2d_fromcontext(C);
wmOrtho2_region_pixelspace(CTX_wm_region(C));
GPU_blend(GPU_BLEND_ALPHA);
GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
for (const Sequence *seq : sequencer_visible_strips_get(C)) {
for (const SeqRetimingKey &key : SEQ_retiming_keys_get(seq)) {
retime_speed_text_draw(C, seq, &key);
}
}
immUnbindProgram();
GPU_blend(GPU_BLEND_NONE);
UI_view2d_text_cache_draw(CTX_wm_region(C));
UI_view2d_view_ortho(v2d); /* 'UI_view2d_text_cache_draw()' messes up current view. */
UI_view2d_view_ortho(timeline_ctx->v2d);
}
/** \} */
void sequencer_draw_retiming(const bContext *C, SeqQuadsBatch *quads)
{
retime_keys_draw(C, quads);
retime_speed_draw(C);
}

View File

@@ -27,9 +27,6 @@
#include "BKE_global.hh"
#include "BKE_sound.h"
#include "GPU_immediate.hh"
#include "GPU_viewport.hh"
#include "ED_anim_api.hh"
#include "ED_markers.hh"
#include "ED_mask.hh"
@@ -44,6 +41,7 @@
#include "SEQ_prefetch.hh"
#include "SEQ_relations.hh"
#include "SEQ_render.hh"
#include "SEQ_retiming.hh"
#include "SEQ_select.hh"
#include "SEQ_sequencer.hh"
#include "SEQ_time.hh"
@@ -73,40 +71,6 @@ using namespace blender::ed::seq;
constexpr float MISSING_ICON_SIZE = 12.0f;
struct StripDrawContext {
Sequence *seq;
/* Strip boundary in timeline space. Content start/end is clamped by left/right handle. */
float content_start, content_end, bottom, top;
float left_handle, right_handle; /* Position in frames. */
float strip_content_top; /* Position in timeline space without content and text overlay. */
float handle_width; /* Width of strip handle in frames. */
float strip_length;
bool can_draw_text_overlay;
bool can_draw_strip_content;
bool strip_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;
bool missing_data_block;
bool missing_media;
};
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. */
SeqQuadsBatch *quads;
};
Vector<Sequence *> sequencer_visible_strips_get(const bContext *C)
{
return sequencer_visible_strips_get(CTX_data_scene(C), UI_view2d_fromcontext(C));
@@ -158,6 +122,8 @@ static TimelineDrawContext timeline_draw_context_get(const bContext *C, SeqQuads
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);
ctx.retiming_selection = SEQ_retiming_selection_get(ctx.ed);
ctx.quads = quads_batch;
return ctx;
@@ -1515,7 +1481,7 @@ static void draw_seq_strips(TimelineDrawContext *timeline_ctx,
}
timeline_ctx->quads->draw();
/* Draw all thumbnails. */
/* Draw all thumbnails and retiming continuity. */
GPU_blend(GPU_BLEND_ALPHA);
for (const StripDrawContext &strip_ctx : strips) {
draw_seq_strip_thumbnail(timeline_ctx->v2d,
@@ -1528,7 +1494,9 @@ static void draw_seq_strips(TimelineDrawContext *timeline_ctx,
timeline_ctx->pixelx,
timeline_ctx->pixely,
round_radius);
sequencer_retiming_draw_continuity(timeline_ctx, strip_ctx);
}
timeline_ctx->quads->draw();
/* Draw parts of strips above thumbnails. */
GPU_blend(GPU_BLEND_ALPHA);
@@ -1539,7 +1507,10 @@ static void draw_seq_strips(TimelineDrawContext *timeline_ctx,
draw_handle_transform_text(timeline_ctx, &strip_ctx, SEQ_HANDLE_LEFT);
draw_handle_transform_text(timeline_ctx, &strip_ctx, SEQ_HANDLE_RIGHT);
draw_seq_text_overlay(timeline_ctx, &strip_ctx);
sequencer_retiming_keys_draw(timeline_ctx, strip_ctx);
sequencer_retiming_speed_draw(timeline_ctx, strip_ctx);
}
timeline_ctx->quads->draw();
draw_strips_foreground(timeline_ctx, strips_batch, strips);
@@ -1919,7 +1890,6 @@ void draw_timeline_seq(const bContext *C, ARegion *region)
draw_timeline_backdrop(&ctx);
draw_timeline_sfra_efra(&ctx);
draw_seq_strips(&ctx, strips_batch);
sequencer_draw_retiming(C, &quads_batch);
draw_timeline_markers(&ctx);
UI_view2d_view_ortho(ctx.v2d);
ANIM_draw_previewrange(C, ctx.v2d, 1);