diff --git a/source/blender/editors/space_sequencer/CMakeLists.txt b/source/blender/editors/space_sequencer/CMakeLists.txt index 2fe7439d926..34a9764877a 100644 --- a/source/blender/editors/space_sequencer/CMakeLists.txt +++ b/source/blender/editors/space_sequencer/CMakeLists.txt @@ -39,6 +39,7 @@ set(SRC sequencer_retiming_draw.cc sequencer_scopes.cc sequencer_select.cc + sequencer_strips_batch.cc sequencer_thumbnails.cc sequencer_timeline_draw.cc sequencer_view.cc @@ -47,6 +48,7 @@ set(SRC sequencer_intern.hh sequencer_quads_batch.hh sequencer_scopes.hh + sequencer_strips_batch.hh ) set(LIB diff --git a/source/blender/editors/space_sequencer/sequencer_drag_drop.cc b/source/blender/editors/space_sequencer/sequencer_drag_drop.cc index e040e4b046c..64d377cf7a3 100644 --- a/source/blender/editors/space_sequencer/sequencer_drag_drop.cc +++ b/source/blender/editors/space_sequencer/sequencer_drag_drop.cc @@ -28,7 +28,6 @@ #include "UI_resources.hh" #include "UI_view2d.hh" -#include "GPU_immediate.hh" #include "GPU_matrix.hh" #include "ED_screen.hh" @@ -49,6 +48,7 @@ /* Own include. */ #include "sequencer_intern.hh" +#include "sequencer_strips_batch.hh" struct SeqDropCoords { float start_frame, channel; @@ -362,6 +362,7 @@ static void get_drag_path(const bContext *C, wmDrag *drag, char r_path[FILE_MAX] static void draw_seq_in_view(bContext *C, wmWindow * /*win*/, wmDrag *drag, const int xy[2]) { + using namespace blender::ed::seq; SeqDropCoords *coords = &g_drop_coords; if (!coords->in_use) { return; @@ -389,20 +390,19 @@ static void draw_seq_in_view(bContext *C, wmWindow * /*win*/, wmDrag *drag, cons } /* Init GPU drawing. */ - GPU_line_width(2.0f); - GPU_blend(GPU_BLEND_ALPHA); - GPU_line_smooth(true); - 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_PREMULT); /* Draw strips. The code here is taken from sequencer_draw. */ float x1 = coords->start_frame; float x2 = coords->start_frame + floorf(strip_len); - float strip_color[3]; + uchar strip_color[4]; + strip_color[3] = 255; uchar text_color[4] = {255, 255, 255, 255}; float pixelx = BLI_rctf_size_x(®ion->v2d.cur) / BLI_rcti_size_x(®ion->v2d.mask); float pixely = BLI_rctf_size_y(®ion->v2d.cur) / BLI_rcti_size_y(®ion->v2d.mask); + StripsDrawBatch batch(pixelx, pixely); + for (int i = 0; i < coords->channel_len; i++) { float y1 = floorf(coords->channel) + i + SEQ_STRIP_OFSBOTTOM; float y2 = floorf(coords->channel) + i + SEQ_STRIP_OFSTOP; @@ -412,42 +412,36 @@ static void draw_seq_in_view(bContext *C, wmWindow * /*win*/, wmDrag *drag, cons * One for video and the other for audio. * The audio channel is added first. */ - UI_GetThemeColor3fv(TH_SEQ_AUDIO, strip_color); + UI_GetThemeColor3ubv(TH_SEQ_AUDIO, strip_color); } else { - UI_GetThemeColor3fv(coords->type, strip_color); + UI_GetThemeColor3ubv(coords->type, strip_color); } - immUniformColor3fvAlpha(strip_color, 0.8f); - immRectf(pos, x1, y1, x2, y2); + SeqStripDrawData &data = batch.add_strip(x1, x2, y2, y1, y2, x1, x2, 0, true); + data.flags |= GPU_SEQ_FLAG_BACKGROUND | GPU_SEQ_FLAG_BORDER | GPU_SEQ_FLAG_SELECTED; + data.col_background = color_pack(strip_color); if (coords->is_intersecting) { - strip_color[0] = 1.0f; - strip_color[1] = strip_color[2] = 0.3f; + strip_color[0] = 255; + strip_color[1] = strip_color[2] = 33; } else { if (coords->channel_len - 1 == i) { text_color[0] = text_color[1] = text_color[2] = 255; - UI_GetThemeColor3fv(TH_SEQ_ACTIVE, strip_color); + UI_GetThemeColor3ubv(TH_SEQ_ACTIVE, strip_color); + data.flags |= GPU_SEQ_FLAG_ACTIVE; } else { text_color[0] = text_color[1] = text_color[2] = 10; - UI_GetThemeColor3fv(TH_SEQ_SELECTED, strip_color); + UI_GetThemeColor3ubv(TH_SEQ_SELECTED, strip_color); } } + strip_color[3] = 204; + data.col_outline = color_pack(strip_color); - /* Draw a 2 pixel border around the strip. */ - immUniformColor3fvAlpha(strip_color, 0.8f); - /* Left */ - immRectf(pos, x1 - pixelx, y1, x1 + pixelx, y2); - /* Bottom */ - immRectf(pos, x1 - pixelx, y1, x2 + pixelx, y1 + 2 * pixely); - /* Right */ - immRectf(pos, x2 - pixelx, y1, x2 + pixelx, y2); - /* Top */ - immRectf(pos, x1 - pixelx, y2 - 2 * pixely, x2 + pixelx, y2); - - float handle_size = 8.0f; /* SEQ_HANDLE_SIZE */ + const bool use_thin_handle = (U.sequencer_editor_flag & USER_SEQ_ED_SIMPLE_TWEAKING) != 0; + const float handle_size = use_thin_handle ? 5.0f : 8.0f; /* Calculate height needed for drawing text on strip. */ float text_margin_y = y2 - min_ff(0.40f, 20 * UI_SCALE_FAC * pixely); @@ -502,13 +496,12 @@ static void draw_seq_in_view(bContext *C, wmWindow * /*win*/, wmDrag *drag, cons UI_view2d_text_cache_add_rectf( ®ion->v2d, &rect, text_display, strlen(text_display), text_color); } + batch.flush_batch(); /* Clean after drawing up. */ UI_Theme_Restore(&theme_state); GPU_matrix_pop(); - immUnbindProgram(); GPU_blend(GPU_BLEND_NONE); - GPU_line_smooth(false); UI_view2d_text_cache_draw(region); } diff --git a/source/blender/editors/space_sequencer/sequencer_strips_batch.cc b/source/blender/editors/space_sequencer/sequencer_strips_batch.cc new file mode 100644 index 00000000000..d86a5c35e11 --- /dev/null +++ b/source/blender/editors/space_sequencer/sequencer_strips_batch.cc @@ -0,0 +1,122 @@ +/* SPDX-FileCopyrightText: 2024 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup spseq + */ + +#include "sequencer_strips_batch.hh" + +#include "GPU_batch.hh" +#include "GPU_batch_presets.hh" +#include "GPU_shader_shared.hh" +#include "GPU_uniform_buffer.hh" + +#include "UI_resources.hh" + +namespace blender::ed::seq { + +uint color_pack(const uchar rgba[4]) +{ + return rgba[0] | (rgba[1] << 8u) | (rgba[2] << 16u) | (rgba[3] << 24u); +} + +float calc_strip_round_radius(float pixely) +{ + float height_pixels = 1.0f / pixely; + if (height_pixels < 16.0f) { + return 0.0f; + } + if (height_pixels < 64.0f) { + return 4.0f; + } + if (height_pixels < 128.0f) { + return 6.0f; + } + return 8.0f; +} + +StripsDrawBatch::StripsDrawBatch(float pixelx, float pixely) : strips_(GPU_SEQ_STRIP_DRAW_DATA_LEN) +{ + context_.pixelx = pixelx; + context_.pixely = pixely; + context_.inv_pixelx = 1.0f / pixelx; + context_.inv_pixely = 1.0f / pixely; + context_.round_radius = calc_strip_round_radius(pixely); + + uchar col[4]; + UI_GetThemeColor3ubv(TH_BACK, col); + col[3] = 255; + context_.col_back = color_pack(col); + + shader_ = GPU_shader_get_builtin_shader(GPU_SHADER_SEQUENCER_STRIPS); + binding_strips_ = GPU_shader_get_ubo_binding(shader_, "strip_data"); + binding_context_ = GPU_shader_get_ubo_binding(shader_, "context_data"); + + ubo_context_ = GPU_uniformbuf_create_ex(sizeof(SeqContextDrawData), &context_, __func__); + ubo_strips_ = GPU_uniformbuf_create(sizeof(SeqStripDrawData) * GPU_SEQ_STRIP_DRAW_DATA_LEN); + + batch_ = GPU_batch_preset_quad(); +} + +StripsDrawBatch::~StripsDrawBatch() +{ + flush_batch(); + + GPU_uniformbuf_unbind(ubo_strips_); + GPU_uniformbuf_free(ubo_strips_); + GPU_uniformbuf_unbind(ubo_context_); + GPU_uniformbuf_free(ubo_context_); +} + +SeqStripDrawData &StripsDrawBatch::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) +{ + if (strips_count_ == GPU_SEQ_STRIP_DRAW_DATA_LEN) { + flush_batch(); + } + + SeqStripDrawData &res = strips_[strips_count_]; + strips_count_++; + + memset(&res, 0, sizeof(res)); + res.content_start = content_start; + res.content_end = content_end; + res.top = top; + res.bottom = bottom; + res.strip_content_top = content_top; + res.left_handle = left_handle; + res.right_handle = right_handle; + res.handle_width = handle_width; + if (single_image) { + res.flags |= GPU_SEQ_FLAG_SINGLE_IMAGE; + } + return res; +} + +void StripsDrawBatch::flush_batch() +{ + if (strips_count_ == 0) { + return; + } + + GPU_uniformbuf_update(ubo_strips_, strips_.data()); + + GPU_shader_bind(shader_); + GPU_uniformbuf_bind(ubo_strips_, binding_strips_); + GPU_uniformbuf_bind(ubo_context_, binding_context_); + + GPU_batch_set_shader(batch_, shader_); + GPU_batch_draw_instance_range(batch_, 0, strips_count_); + strips_count_ = 0; +} + +} // namespace blender::ed::seq diff --git a/source/blender/editors/space_sequencer/sequencer_strips_batch.hh b/source/blender/editors/space_sequencer/sequencer_strips_batch.hh new file mode 100644 index 00000000000..694c5f583f4 --- /dev/null +++ b/source/blender/editors/space_sequencer/sequencer_strips_batch.hh @@ -0,0 +1,54 @@ +/* SPDX-FileCopyrightText: 2024 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup spseq + */ + +#pragma once + +#include "BLI_array.hh" +#include "GPU_shader_shared.hh" + +struct GPUShader; +struct GPUUniformBuf; + +namespace blender::gpu { +class Batch; +} + +namespace blender::ed::seq { + +class StripsDrawBatch { + SeqContextDrawData context_; + Array strips_; + GPUUniformBuf *ubo_context_ = nullptr; + GPUUniformBuf *ubo_strips_ = nullptr; + GPUShader *shader_ = nullptr; + gpu::Batch *batch_ = nullptr; + int binding_context_ = 0; + int binding_strips_ = 0; + int strips_count_ = 0; + + public: + StripsDrawBatch(float pixelx, float pixely); + ~StripsDrawBatch(); + + 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); + + void flush_batch(); +}; + +uint color_pack(const uchar rgba[4]); +float calc_strip_round_radius(float pixely); + +} // namespace blender::ed::seq diff --git a/source/blender/editors/space_sequencer/sequencer_timeline_draw.cc b/source/blender/editors/space_sequencer/sequencer_timeline_draw.cc index f0f0d70f3f4..fb08d429ec5 100644 --- a/source/blender/editors/space_sequencer/sequencer_timeline_draw.cc +++ b/source/blender/editors/space_sequencer/sequencer_timeline_draw.cc @@ -27,11 +27,7 @@ #include "BKE_global.hh" #include "BKE_sound.h" -#include "GPU_batch.hh" -#include "GPU_batch_presets.hh" #include "GPU_immediate.hh" -#include "GPU_shader_shared.hh" -#include "GPU_uniform_buffer.hh" #include "GPU_viewport.hh" #include "ED_anim_api.hh" @@ -68,8 +64,10 @@ /* Own include. */ #include "sequencer_intern.hh" #include "sequencer_quads_batch.hh" +#include "sequencer_strips_batch.hh" using namespace blender; +using namespace blender::ed::seq; #define MUTE_ALPHA 120 @@ -1276,115 +1274,8 @@ static void visible_strips_ordered_get(TimelineDrawContext *timeline_ctx, } } -static uint color_pack(const uchar rgba[4]) -{ - return rgba[0] | (rgba[1] << 8u) | (rgba[2] << 16u) | (rgba[3] << 24u); -} - -static float calc_strip_round_radius(float pixely) -{ - float height_pixels = 1.0f / pixely; - if (height_pixels < 16.0f) { - return 0.0f; - } - if (height_pixels < 64.0f) { - return 4.0f; - } - if (height_pixels < 128.0f) { - return 6.0f; - } - return 8.0f; -} - -class SeqStripsBatch { - SeqContextDrawData context_; - Array strips_; - GPUUniformBuf *ubo_context_ = nullptr; - GPUUniformBuf *ubo_strips_ = nullptr; - GPUShader *shader_ = nullptr; - gpu::Batch *batch_ = nullptr; - int binding_context_ = 0; - int binding_strips_ = 0; - int strips_count_ = 0; - - public: - SeqStripsBatch(float pixelx, float pixely) : strips_(GPU_SEQ_STRIP_DRAW_DATA_LEN) - { - context_.pixelx = pixelx; - context_.pixely = pixely; - context_.inv_pixelx = 1.0f / pixelx; - context_.inv_pixely = 1.0f / pixely; - context_.round_radius = calc_strip_round_radius(pixely); - - uchar col[4]; - UI_GetThemeColor3ubv(TH_BACK, col); - col[3] = 255; - context_.col_back = color_pack(col); - - shader_ = GPU_shader_get_builtin_shader(GPU_SHADER_SEQUENCER_STRIPS); - binding_strips_ = GPU_shader_get_ubo_binding(shader_, "strip_data"); - binding_context_ = GPU_shader_get_ubo_binding(shader_, "context_data"); - - ubo_context_ = GPU_uniformbuf_create_ex(sizeof(SeqContextDrawData), &context_, __func__); - ubo_strips_ = GPU_uniformbuf_create(sizeof(SeqStripDrawData) * GPU_SEQ_STRIP_DRAW_DATA_LEN); - - batch_ = GPU_batch_preset_quad(); - } - - ~SeqStripsBatch() - { - flush_batch(); - - GPU_uniformbuf_unbind(ubo_strips_); - GPU_uniformbuf_free(ubo_strips_); - GPU_uniformbuf_unbind(ubo_context_); - GPU_uniformbuf_free(ubo_context_); - } - - SeqStripDrawData &add_strip(const StripDrawContext &strip) - { - if (strips_count_ == GPU_SEQ_STRIP_DRAW_DATA_LEN) { - flush_batch(); - } - - SeqStripDrawData &res = strips_[strips_count_]; - strips_count_++; - - memset(&res, 0, sizeof(res)); - res.content_start = strip.content_start; - res.content_end = strip.content_end; - res.top = strip.top; - res.bottom = strip.bottom; - res.strip_content_top = strip.strip_content_top; - res.left_handle = strip.left_handle; - res.right_handle = strip.right_handle; - res.handle_width = strip.handle_width; - if (strip.is_single_image) { - res.flags |= GPU_SEQ_FLAG_SINGLE_IMAGE; - } - return res; - } - - void flush_batch() - { - if (strips_count_ == 0) { - return; - } - - GPU_uniformbuf_update(ubo_strips_, strips_.data()); - - GPU_shader_bind(shader_); - GPU_uniformbuf_bind(ubo_strips_, binding_strips_); - GPU_uniformbuf_bind(ubo_context_, binding_context_); - - GPU_batch_set_shader(batch_, shader_); - GPU_batch_draw_instance_range(batch_, 0, strips_count_); - strips_count_ = 0; - } -}; - static void draw_strips_background(TimelineDrawContext *timeline_ctx, - SeqStripsBatch &strips_batch, + StripsDrawBatch &strips_batch, const Vector &strips) { GPU_blend(GPU_BLEND_ALPHA_PREMULT); @@ -1392,12 +1283,19 @@ static void draw_strips_background(TimelineDrawContext *timeline_ctx, const bool show_overlay = (timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) != 0; const Scene *scene = timeline_ctx->scene; for (const StripDrawContext &strip : strips) { - SeqStripDrawData &data = strips_batch.add_strip(strip); - - data.flags |= GPU_SEQ_FLAG_BACKGROUND_PART; + SeqStripDrawData &data = strips_batch.add_strip(strip.content_start, + strip.content_end, + strip.top, + strip.bottom, + strip.strip_content_top, + strip.left_handle, + strip.right_handle, + strip.handle_width, + strip.is_single_image); /* Background color. */ uchar col[4]; + data.flags |= GPU_SEQ_FLAG_BACKGROUND; color3ubv_from_seq(scene, strip.seq, strip.show_strip_color_tag, col); col[3] = mute_alpha_factor_get(timeline_ctx->channels, strip.seq); /* Muted strips: turn almost gray. */ @@ -1452,7 +1350,7 @@ static void draw_strips_background(TimelineDrawContext *timeline_ctx, } static void draw_strips_foreground(TimelineDrawContext *timeline_ctx, - SeqStripsBatch &strips_batch, + StripsDrawBatch &strips_batch, const Vector &strips) { GPU_blend(GPU_BLEND_ALPHA_PREMULT); @@ -1463,7 +1361,16 @@ static void draw_strips_foreground(TimelineDrawContext *timeline_ctx, uchar col[4]; for (const StripDrawContext &strip : strips) { - SeqStripDrawData &data = strips_batch.add_strip(strip); + SeqStripDrawData &data = strips_batch.add_strip(strip.content_start, + strip.content_end, + strip.top, + strip.bottom, + strip.strip_content_top, + strip.left_handle, + strip.right_handle, + strip.handle_width, + strip.is_single_image); + data.flags |= GPU_SEQ_FLAG_BORDER; /* Missing media state. */ if (strip.missing_data_block || strip.missing_media) { @@ -1562,7 +1469,7 @@ static void draw_strips_foreground(TimelineDrawContext *timeline_ctx, } static void draw_seq_strips(TimelineDrawContext *timeline_ctx, - SeqStripsBatch &strips_batch, + StripsDrawBatch &strips_batch, const Vector &strips) { if (strips.is_empty()) { @@ -1624,7 +1531,7 @@ static void draw_seq_strips(TimelineDrawContext *timeline_ctx, GPU_blend(GPU_BLEND_NONE); } -static void draw_seq_strips(TimelineDrawContext *timeline_ctx, SeqStripsBatch &strips_batch) +static void draw_seq_strips(TimelineDrawContext *timeline_ctx, StripsDrawBatch &strips_batch) { if (timeline_ctx->ed == nullptr) { return; @@ -1982,7 +1889,7 @@ void draw_timeline_seq(const bContext *C, ARegion *region) { SeqQuadsBatch quads_batch; TimelineDrawContext ctx = timeline_draw_context_get(C, &quads_batch); - SeqStripsBatch strips_batch(ctx.pixelx, ctx.pixely); + StripsDrawBatch strips_batch(ctx.pixelx, ctx.pixely); draw_timeline_pre_view_callbacks(&ctx); UI_ThemeClearColor(TH_BACK); diff --git a/source/blender/gpu/GPU_shader_shared.hh b/source/blender/gpu/GPU_shader_shared.hh index fae5da656a2..32f22fef7a1 100644 --- a/source/blender/gpu/GPU_shader_shared.hh +++ b/source/blender/gpu/GPU_shader_shared.hh @@ -93,7 +93,7 @@ BLI_STATIC_ASSERT_ALIGN(MultiIconCallData, 16) #define GPU_SEQ_STRIP_DRAW_DATA_LEN 256 enum eGPUSeqFlags : uint32_t { - GPU_SEQ_FLAG_BACKGROUND_PART = (1u << 0u), + GPU_SEQ_FLAG_BACKGROUND = (1u << 0u), GPU_SEQ_FLAG_SINGLE_IMAGE = (1u << 1u), GPU_SEQ_FLAG_COLOR_BAND = (1u << 2u), GPU_SEQ_FLAG_TRANSITION = (1u << 3u), @@ -104,6 +104,7 @@ enum eGPUSeqFlags : uint32_t { GPU_SEQ_FLAG_ACTIVE = (1u << 8u), GPU_SEQ_FLAG_HIGHLIGHT = (1u << 9u), GPU_SEQ_FLAG_HANDLES = (1u << 10u), + GPU_SEQ_FLAG_BORDER = (1u << 11u), }; /* VSE per-strip data for timeline rendering. */ diff --git a/source/blender/gpu/shaders/gpu_shader_sequencer_strips_frag.glsl b/source/blender/gpu/shaders/gpu_shader_sequencer_strips_frag.glsl index 8cb3ed7b6c9..3c9ffa6c3c2 100644 --- a/source/blender/gpu/shaders/gpu_shader_sequencer_strips_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_sequencer_strips_frag.glsl @@ -61,10 +61,8 @@ void main() vec4 col = vec4(0.0); - bool back_part = (strip.flags & GPU_SEQ_FLAG_BACKGROUND_PART) != 0; - - if (back_part) { - + /* Background. */ + if ((strip.flags & GPU_SEQ_FLAG_BACKGROUND) != 0) { col = unpackUnorm4x8(strip.col_background); /* Darker background for multi-image strip hold still regions. */ if ((strip.flags & GPU_SEQ_FLAG_SINGLE_IMAGE) == 0) { @@ -72,80 +70,79 @@ void main() col.rgb = color_shade(col.rgb, -35.0); } } - - /* Color band. */ - if ((strip.flags & GPU_SEQ_FLAG_COLOR_BAND) != 0) { - if (co.y < strip.strip_content_top) { - col.rgb = unpackUnorm4x8(strip.col_color_band).rgb; - /* Darker line to better separate the color band. */ - if (co.y > strip.strip_content_top - context_data.pixely) { - col.rgb = color_shade(col.rgb, -20.0); - } - } - } - - /* Transition. */ - if ((strip.flags & GPU_SEQ_FLAG_TRANSITION) != 0) { - if (co.x >= strip.content_start && co.x <= strip.content_end && - co.y < strip.strip_content_top) - { - float diag_y = strip.strip_content_top - (strip.strip_content_top - strip.bottom) * - (co.x - strip.content_start) / - (strip.content_end - strip.content_start); - uint transition_color = co.y <= diag_y ? strip.col_transition_in : - strip.col_transition_out; - col.rgb = unpackUnorm4x8(transition_color).rgb; - } - } - - col.rgb *= col.a; /* Premultiply alpha. */ } - else { - /* Missing media. */ - if ((strip.flags & GPU_SEQ_FLAG_MISSING_TITLE) != 0) { - if (co.y > strip.strip_content_top) { - col = blend_color(col, vec4(112.0 / 255.0, 0.0, 0.0, 230.0 / 255.0)); - } - } - if ((strip.flags & GPU_SEQ_FLAG_MISSING_CONTENT) != 0) { - if (co.y <= strip.strip_content_top) { - col = blend_color(col, vec4(64.0 / 255.0, 0.0, 0.0, 230.0 / 255.0)); - } - } - /* Locked. */ - if ((strip.flags & GPU_SEQ_FLAG_LOCKED) != 0) { - if (co.y <= strip.strip_content_top) { - float phase = mod(gl_FragCoord.x + gl_FragCoord.y, 12.0); - if (phase >= 8.0) { - col = blend_color(col, vec4(0.0, 0.0, 0.0, 0.25)); - } + /* Color band. */ + if ((strip.flags & GPU_SEQ_FLAG_COLOR_BAND) != 0) { + if (co.y < strip.strip_content_top) { + col.rgb = unpackUnorm4x8(strip.col_color_band).rgb; + /* Darker line to better separate the color band. */ + if (co.y > strip.strip_content_top - context_data.pixely) { + col.rgb = color_shade(col.rgb, -20.0); } } + } - /* Highlight. */ - if ((strip.flags & GPU_SEQ_FLAG_HIGHLIGHT) != 0) { - col = blend_color(col, vec4(1.0, 1.0, 1.0, 48.0 / 255.0)); + /* Transition. */ + if ((strip.flags & GPU_SEQ_FLAG_TRANSITION) != 0) { + if (co.x >= strip.content_start && co.x <= strip.content_end && co.y < strip.strip_content_top) + { + float diag_y = strip.strip_content_top - (strip.strip_content_top - strip.bottom) * + (co.x - strip.content_start) / + (strip.content_end - strip.content_start); + uint transition_color = co.y <= diag_y ? strip.col_transition_in : strip.col_transition_out; + col.rgb = unpackUnorm4x8(transition_color).rgb; } + } - /* Handles. */ - if ((strip.flags & GPU_SEQ_FLAG_HANDLES) != 0) { - if (co.x >= strip.left_handle && co.x < strip.left_handle + strip.handle_width) { - col = blend_color(col, unpackUnorm4x8(strip.col_handle_left)); - } - if (co.x > strip.right_handle - strip.handle_width && co.x <= strip.right_handle) { - col = blend_color(col, unpackUnorm4x8(strip.col_handle_right)); + /* Previous parts were all assigning color (not blending it), + * make sure from now on alpha is premultiplied. */ + col.rgb *= col.a; + + /* Missing media. */ + if ((strip.flags & GPU_SEQ_FLAG_MISSING_TITLE) != 0) { + if (co.y > strip.strip_content_top) { + col = blend_color(col, vec4(112.0 / 255.0, 0.0, 0.0, 230.0 / 255.0)); + } + } + if ((strip.flags & GPU_SEQ_FLAG_MISSING_CONTENT) != 0) { + if (co.y <= strip.strip_content_top) { + col = blend_color(col, vec4(64.0 / 255.0, 0.0, 0.0, 230.0 / 255.0)); + } + } + + /* Locked. */ + if ((strip.flags & GPU_SEQ_FLAG_LOCKED) != 0) { + if (co.y <= strip.strip_content_top) { + float phase = mod(gl_FragCoord.x + gl_FragCoord.y, 12.0); + if (phase >= 8.0) { + col = blend_color(col, vec4(0.0, 0.0, 0.0, 0.25)); } } } + /* Highlight. */ + if ((strip.flags & GPU_SEQ_FLAG_HIGHLIGHT) != 0) { + col = blend_color(col, vec4(1.0, 1.0, 1.0, 48.0 / 255.0)); + } + + /* Handles. */ + if ((strip.flags & GPU_SEQ_FLAG_HANDLES) != 0) { + if (co.x >= strip.left_handle && co.x < strip.left_handle + strip.handle_width) { + col = blend_color(col, unpackUnorm4x8(strip.col_handle_left)); + } + if (co.x > strip.right_handle - strip.handle_width && co.x <= strip.right_handle) { + col = blend_color(col, unpackUnorm4x8(strip.col_handle_right)); + } + } + /* Outside of strip rounded rectangle? */ if (sdf > 0.0) { col = vec4(0.0); } - /* Outline. */ - if (!back_part) { + /* Outline / border. */ + if ((strip.flags & GPU_SEQ_FLAG_BORDER) != 0) { bool selected = (strip.flags & GPU_SEQ_FLAG_SELECTED) != 0; vec4 col_outline = unpackUnorm4x8(strip.col_outline); if (selected) {