VSE: Rounded corners for timeline strips
VSE timeline strips now have rounded corners. Strip corner rounding radius is 4, 6 or 8px depending on strip height (if strip is too narrow to fit rounding, then rounding is turned off). This is achieved with a dedicated GPU shader for drawing most of VSE strip widget, that it could do proper rounded corner masking. More details and images in the PR. Pull Request: https://projects.blender.org/blender/blender/pulls/122576
This commit is contained in:
committed by
Aras Pranckevicius
parent
a7171e0391
commit
7fdfa47f23
@@ -130,8 +130,10 @@ void draw_seq_strip_thumbnail(View2D *v2d,
|
||||
Sequence *seq,
|
||||
float y1,
|
||||
float y2,
|
||||
float y_top,
|
||||
float pixelx,
|
||||
float pixely);
|
||||
float pixely,
|
||||
float round_radius);
|
||||
|
||||
/* sequencer_draw_channels.c */
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_ghash.h"
|
||||
#include "BLI_math_vector.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_global.hh"
|
||||
@@ -34,6 +36,8 @@
|
||||
/* Own include. */
|
||||
#include "sequencer_intern.hh"
|
||||
|
||||
using namespace blender;
|
||||
|
||||
struct ThumbnailDrawJob {
|
||||
SeqRenderData context;
|
||||
GHash *sequences_ghash;
|
||||
@@ -429,14 +433,79 @@ static ImBuf *sequencer_thumbnail_closest_from_memory(const SeqRenderData *conte
|
||||
return closest_in_memory;
|
||||
}
|
||||
|
||||
static void make_ibuf_semitransparent(ImBuf *ibuf)
|
||||
{
|
||||
const uchar alpha = 120;
|
||||
if (ibuf->byte_buffer.data) {
|
||||
uchar *buf = ibuf->byte_buffer.data;
|
||||
for (int pixel = ibuf->x * ibuf->y; pixel--; buf += 4) {
|
||||
buf[3] = alpha;
|
||||
}
|
||||
}
|
||||
if (ibuf->float_buffer.data) {
|
||||
float *buf = ibuf->float_buffer.data;
|
||||
for (int pixel = ibuf->x * ibuf->y; pixel--; buf += ibuf->channels) {
|
||||
buf[3] = (alpha / 255.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Signed distance to rounded box, centered at origin.
|
||||
* Reference: https://iquilezles.org/articles/distfunctions2d/ */
|
||||
static float sdf_rounded_box(float2 pos, float2 size, float radius)
|
||||
{
|
||||
float2 q = math::abs(pos) - size + radius;
|
||||
return math::min(math::max(q.x, q.y), 0.0f) + math::length(math::max(q, float2(0.0f))) - radius;
|
||||
}
|
||||
|
||||
static void eval_round_corners_pixel(
|
||||
ImBuf *ibuf, float radius, float2 bmin, float2 bmax, float2 pos)
|
||||
{
|
||||
int ix = int(pos.x);
|
||||
int iy = int(pos.y);
|
||||
if (ix < 0 || ix >= ibuf->x || iy < 0 || iy >= ibuf->y) {
|
||||
return;
|
||||
}
|
||||
float2 center = (bmin + bmax) * 0.5f;
|
||||
float2 size = (bmax - bmin) * 0.5f;
|
||||
float d = sdf_rounded_box(pos - center, size, radius);
|
||||
if (d <= 0.0f) {
|
||||
return;
|
||||
}
|
||||
/* Outside of rounded rectangle, set pixel alpha to zero. */
|
||||
if (ibuf->byte_buffer.data != nullptr) {
|
||||
int64_t ofs = (int64_t(iy) * ibuf->x + ix) * 4;
|
||||
ibuf->byte_buffer.data[ofs + 3] = 0;
|
||||
}
|
||||
if (ibuf->float_buffer.data != nullptr) {
|
||||
int64_t ofs = (int64_t(iy) * ibuf->x + ix) * ibuf->channels;
|
||||
ibuf->float_buffer.data[ofs + 3] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
static void make_ibuf_round_corners(ImBuf *ibuf, float radius, float2 bmin, float2 bmax)
|
||||
{
|
||||
/* Evaluate radius*radius squares at corners. */
|
||||
for (int by = 0; by < radius; by++) {
|
||||
for (int bx = 0; bx < radius; bx++) {
|
||||
eval_round_corners_pixel(ibuf, radius, bmin, bmax, float2(bmin.x + bx, bmin.y + by));
|
||||
eval_round_corners_pixel(ibuf, radius, bmin, bmax, float2(bmax.x - bx, bmin.y + by));
|
||||
eval_round_corners_pixel(ibuf, radius, bmin, bmax, float2(bmin.x + bx, bmax.y - by));
|
||||
eval_round_corners_pixel(ibuf, radius, bmin, bmax, float2(bmax.x - bx, bmax.y - by));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void draw_seq_strip_thumbnail(View2D *v2d,
|
||||
const bContext *C,
|
||||
Scene *scene,
|
||||
Sequence *seq,
|
||||
float y1,
|
||||
float y2,
|
||||
float y_top,
|
||||
float pixelx,
|
||||
float pixely)
|
||||
float pixely,
|
||||
float round_radius)
|
||||
{
|
||||
SpaceSeq *sseq = CTX_wm_space_seq(C);
|
||||
if ((sseq->flag & SEQ_SHOW_OVERLAY) == 0 ||
|
||||
@@ -475,12 +544,14 @@ void draw_seq_strip_thumbnail(View2D *v2d,
|
||||
|
||||
float thumb_y_end = y1 + thumb_height;
|
||||
|
||||
const float seq_left_handle = SEQ_time_left_handle_frame_get(scene, seq);
|
||||
const float seq_right_handle = SEQ_time_right_handle_frame_get(scene, seq);
|
||||
|
||||
float cut_off = 0;
|
||||
float upper_thumb_bound = SEQ_time_has_right_still_frames(scene, seq) ?
|
||||
(seq->start + seq->len) :
|
||||
SEQ_time_right_handle_frame_get(scene, seq);
|
||||
float upper_thumb_bound = SEQ_time_has_right_still_frames(scene, seq) ? (seq->start + seq->len) :
|
||||
seq_right_handle;
|
||||
if (seq->type == SEQ_TYPE_IMAGE) {
|
||||
upper_thumb_bound = SEQ_time_right_handle_frame_get(scene, seq);
|
||||
upper_thumb_bound = seq_right_handle;
|
||||
}
|
||||
|
||||
float timeline_frame = SEQ_render_thumbnail_first_frame_get(scene, seq, thumb_width, &v2d->cur);
|
||||
@@ -505,8 +576,8 @@ void draw_seq_strip_thumbnail(View2D *v2d,
|
||||
}
|
||||
|
||||
/* Set the clipping bound to show the left handle moving over thumbs and not shift thumbs. */
|
||||
if (IN_RANGE_INCL(SEQ_time_left_handle_frame_get(scene, seq), timeline_frame, thumb_x_end)) {
|
||||
cut_off = SEQ_time_left_handle_frame_get(scene, seq) - timeline_frame;
|
||||
if (IN_RANGE_INCL(seq_left_handle, timeline_frame, thumb_x_end)) {
|
||||
cut_off = seq_left_handle - timeline_frame;
|
||||
clipped = true;
|
||||
}
|
||||
|
||||
@@ -552,35 +623,37 @@ void draw_seq_strip_thumbnail(View2D *v2d,
|
||||
/* Transparency on mute. */
|
||||
bool muted = channels ? SEQ_render_is_muted(channels, seq) : false;
|
||||
if (muted) {
|
||||
const uchar alpha = 120;
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
if (ibuf->byte_buffer.data) {
|
||||
uchar *buf = ibuf->byte_buffer.data;
|
||||
for (int pixel = ibuf->x * ibuf->y; pixel--; buf += 4) {
|
||||
buf[3] = alpha;
|
||||
}
|
||||
}
|
||||
else if (ibuf->float_buffer.data) {
|
||||
float *buf = ibuf->float_buffer.data;
|
||||
for (int pixel = ibuf->x * ibuf->y; pixel--; buf += ibuf->channels) {
|
||||
buf[3] = (alpha / 255.0f);
|
||||
}
|
||||
make_ibuf_semitransparent(ibuf);
|
||||
}
|
||||
|
||||
/* If thumbnail start or end falls within strip corner rounding area,
|
||||
* we need to manually set thumbnail pixels that are outside of rounded
|
||||
* rectangle to be transparent. Ideally this would be done on the GPU
|
||||
* while drawing, but since rendering is done through OCIO shaders that
|
||||
* is hard to do. */
|
||||
const float xpos = timeline_frame + cut_off;
|
||||
const float radius = ibuf->y * round_radius * pixely / (y2 - y1);
|
||||
if (radius > 0.9f) {
|
||||
if (xpos < seq_left_handle + round_radius * pixelx ||
|
||||
thumb_x_end > seq_right_handle - round_radius * pixelx)
|
||||
{
|
||||
/* Work on a copy of the thumbnail image, so that corner rounding
|
||||
* is not stored into thumbnail cache. */
|
||||
ImBuf *copy = IMB_dupImBuf(ibuf);
|
||||
IMB_freeImBuf(ibuf);
|
||||
ibuf = copy;
|
||||
|
||||
float round_y_top = ibuf->y * (y_top - y1) / (y2 - y1);
|
||||
make_ibuf_round_corners(ibuf,
|
||||
radius,
|
||||
float2((seq_left_handle - xpos) / zoom_x, 0),
|
||||
float2((seq_right_handle - xpos) / zoom_x, round_y_top));
|
||||
}
|
||||
}
|
||||
|
||||
ED_draw_imbuf_ctx_clipping(C,
|
||||
ibuf,
|
||||
timeline_frame + cut_off,
|
||||
y1,
|
||||
true,
|
||||
timeline_frame + cut_off,
|
||||
y1,
|
||||
thumb_x_end,
|
||||
thumb_y_end,
|
||||
zoom_x,
|
||||
zoom_y);
|
||||
ED_draw_imbuf_ctx_clipping(
|
||||
C, ibuf, xpos, y1, true, xpos, y1, thumb_x_end, thumb_y_end, zoom_x, zoom_y);
|
||||
IMB_freeImBuf(ibuf);
|
||||
GPU_blend(GPU_BLEND_NONE);
|
||||
cut_off = 0;
|
||||
timeline_frame = SEQ_render_thumbnail_next_frame_get(scene, seq, timeline_frame, thumb_width);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_string_utils.hh"
|
||||
#include "BLI_threads.h"
|
||||
@@ -26,7 +27,11 @@
|
||||
#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"
|
||||
@@ -64,6 +69,8 @@
|
||||
#include "sequencer_intern.hh"
|
||||
#include "sequencer_quads_batch.hh"
|
||||
|
||||
using namespace blender;
|
||||
|
||||
#define MUTE_ALPHA 120
|
||||
|
||||
constexpr float MISSING_ICON_SIZE = 16.0f;
|
||||
@@ -102,15 +109,15 @@ struct TimelineDrawContext {
|
||||
SeqQuadsBatch *quads;
|
||||
};
|
||||
|
||||
blender::Vector<Sequence *> sequencer_visible_strips_get(const bContext *C)
|
||||
Vector<Sequence *> sequencer_visible_strips_get(const bContext *C)
|
||||
{
|
||||
return sequencer_visible_strips_get(CTX_data_scene(C), UI_view2d_fromcontext(C));
|
||||
}
|
||||
|
||||
blender::Vector<Sequence *> sequencer_visible_strips_get(const Scene *scene, const View2D *v2d)
|
||||
Vector<Sequence *> sequencer_visible_strips_get(const Scene *scene, const View2D *v2d)
|
||||
{
|
||||
const Editing *ed = SEQ_editing_get(scene);
|
||||
blender::Vector<Sequence *> strips;
|
||||
Vector<Sequence *> strips;
|
||||
|
||||
LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) {
|
||||
if (min_ii(SEQ_time_left_handle_frame_get(scene, seq), SEQ_time_start_frame_get(seq)) >
|
||||
@@ -214,7 +221,7 @@ static void strip_draw_context_set_strip_content_visibility(TimelineDrawContext
|
||||
|
||||
static StripDrawContext strip_draw_context_get(TimelineDrawContext *ctx, Sequence *seq)
|
||||
{
|
||||
using namespace blender::seq;
|
||||
using namespace seq;
|
||||
StripDrawContext strip_ctx;
|
||||
Scene *scene = ctx->scene;
|
||||
|
||||
@@ -609,9 +616,11 @@ static void draw_seq_waveform_overlay(TimelineDrawContext *timeline_ctx,
|
||||
}
|
||||
}
|
||||
|
||||
static void drawmeta_contents(TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx)
|
||||
static void drawmeta_contents(TimelineDrawContext *timeline_ctx,
|
||||
const StripDrawContext *strip_ctx,
|
||||
float corner_radius)
|
||||
{
|
||||
using namespace blender::seq;
|
||||
using namespace seq;
|
||||
Sequence *seq_meta = strip_ctx->seq;
|
||||
if (!strip_ctx->can_draw_strip_content || (timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) == 0) {
|
||||
return;
|
||||
@@ -661,15 +670,15 @@ static void drawmeta_contents(TimelineDrawContext *timeline_ctx, const StripDraw
|
||||
|
||||
col[3] = 196; /* Alpha, used for all meta children. */
|
||||
|
||||
const float meta_x1 = strip_ctx->left_handle + corner_radius * 0.8f * timeline_ctx->pixelx;
|
||||
const float meta_x2 = strip_ctx->right_handle - corner_radius * 0.8f * timeline_ctx->pixelx;
|
||||
|
||||
/* Draw only immediate children (1 level depth). */
|
||||
LISTBASE_FOREACH (Sequence *, seq, meta_seqbase) {
|
||||
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 > strip_ctx->right_handle || enddisp < strip_ctx->left_handle) == 0) {
|
||||
float x1_chan = SEQ_time_left_handle_frame_get(scene, seq) + offset;
|
||||
float x2_chan = SEQ_time_right_handle_frame_get(scene, seq) + offset;
|
||||
if (x1_chan <= meta_x2 && x2_chan >= meta_x1) {
|
||||
float y_chan = (seq->machine - chan_min) / float(chan_range) * draw_range;
|
||||
float x1_chan = startdisp;
|
||||
float x2_chan = enddisp;
|
||||
float y1_chan, y2_chan;
|
||||
|
||||
if (seq->type == SEQ_TYPE_COLOR) {
|
||||
@@ -696,12 +705,8 @@ static void drawmeta_contents(TimelineDrawContext *timeline_ctx, const StripDraw
|
||||
}
|
||||
|
||||
/* Clamp within parent sequence strip bounds. */
|
||||
if (x1_chan < strip_ctx->left_handle) {
|
||||
x1_chan = strip_ctx->left_handle;
|
||||
}
|
||||
if (x2_chan > strip_ctx->right_handle) {
|
||||
x2_chan = strip_ctx->right_handle;
|
||||
}
|
||||
x1_chan = max_ff(x1_chan, meta_x1);
|
||||
x2_chan = min_ff(x2_chan, meta_x2);
|
||||
|
||||
y1_chan = strip_ctx->bottom + y_chan + (draw_height * SEQ_STRIP_OFSBOTTOM);
|
||||
y2_chan = strip_ctx->bottom + y_chan + (draw_height * SEQ_STRIP_OFSTOP);
|
||||
@@ -768,119 +773,6 @@ float sequence_handle_size_get_clamped(const Scene *scene, Sequence *seq, const
|
||||
4.0f));
|
||||
}
|
||||
|
||||
static void draw_seq_handle(const TimelineDrawContext *timeline_ctx,
|
||||
const StripDrawContext *strip_ctx,
|
||||
eSeqHandle handle)
|
||||
{
|
||||
const Sequence *seq = strip_ctx->seq;
|
||||
const bool show_handles = (U.sequencer_editor_flag & USER_SEQ_ED_SIMPLE_TWEAKING) == 0;
|
||||
const bool strip_selected = (seq->flag & SELECT) != 0;
|
||||
const bool handle_selected = ED_sequencer_handle_is_selected(seq, handle);
|
||||
|
||||
if ((!strip_selected || !handle_selected) && !show_handles) {
|
||||
return;
|
||||
}
|
||||
if (SEQ_transform_is_locked(timeline_ctx->channels, seq)) {
|
||||
return;
|
||||
}
|
||||
if ((seq->type & SEQ_TYPE_EFFECT) && SEQ_effect_get_num_inputs(seq->type) > 0) {
|
||||
return;
|
||||
}
|
||||
if (!ED_sequencer_can_select_handle(timeline_ctx->scene, seq, timeline_ctx->v2d)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uchar col[4];
|
||||
if (strip_selected && handle_selected && seq == SEQ_select_active_get(timeline_ctx->scene)) {
|
||||
UI_GetThemeColor4ubv(TH_SEQ_ACTIVE, col);
|
||||
}
|
||||
else if (strip_selected && handle_selected) {
|
||||
UI_GetThemeColor4ubv(TH_SEQ_SELECTED, col);
|
||||
}
|
||||
else {
|
||||
col[0] = col[1] = col[2] = 0;
|
||||
col[3] = 50;
|
||||
}
|
||||
|
||||
rctf handle_rect = {0, 0, strip_ctx->bottom, strip_ctx->top};
|
||||
if (handle == SEQ_HANDLE_LEFT) {
|
||||
handle_rect.xmin = strip_ctx->left_handle;
|
||||
handle_rect.xmax = strip_ctx->left_handle + strip_ctx->handle_width;
|
||||
}
|
||||
else if (handle == SEQ_HANDLE_RIGHT) {
|
||||
handle_rect.xmin = strip_ctx->right_handle - strip_ctx->handle_width;
|
||||
handle_rect.xmax = strip_ctx->right_handle;
|
||||
}
|
||||
|
||||
timeline_ctx->quads->add_quad(
|
||||
handle_rect.xmin, handle_rect.ymin, handle_rect.xmax, handle_rect.ymax, col);
|
||||
}
|
||||
|
||||
/* Strip border, and outline for selected/active strips. */
|
||||
static void draw_seq_outline(TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx)
|
||||
{
|
||||
const Sequence *seq = strip_ctx->seq;
|
||||
const bool selected = seq->flag & SELECT;
|
||||
const bool active = strip_ctx->is_active_strip;
|
||||
|
||||
/* Outline color. */
|
||||
uchar col[4];
|
||||
if (selected) {
|
||||
UI_GetThemeColor3ubv(active ? TH_SEQ_ACTIVE : TH_SEQ_SELECTED, col);
|
||||
}
|
||||
else {
|
||||
/* Color for unselected strips is a bit darker than the background. */
|
||||
UI_GetThemeColorShade3ubv(TH_BACK, -40, col);
|
||||
}
|
||||
col[3] = 255;
|
||||
|
||||
/* Outline while translating strips:
|
||||
* - Slightly lighter.
|
||||
* - Red when overlapping with other strips. */
|
||||
const eSeqOverlapMode overlap_mode = SEQ_tool_settings_overlap_mode_get(timeline_ctx->scene);
|
||||
if ((G.moving & G_TRANSFORM_SEQ) && selected && overlap_mode != SEQ_OVERLAP_OVERWRITE) {
|
||||
if (seq->flag & SEQ_OVERLAP) {
|
||||
col[0] = 255;
|
||||
col[1] = col[2] = 33;
|
||||
}
|
||||
else {
|
||||
UI_GetColorPtrShade3ubv(col, col, 70);
|
||||
}
|
||||
}
|
||||
|
||||
/* Selected outline: 2px wide outline, plus 1px wide background inset. */
|
||||
const float x0 = strip_ctx->left_handle;
|
||||
const float x1 = strip_ctx->right_handle;
|
||||
const float y0 = strip_ctx->bottom;
|
||||
const float y1 = strip_ctx->top;
|
||||
const float dx = timeline_ctx->pixelx;
|
||||
const float dy = timeline_ctx->pixely;
|
||||
|
||||
if (selected) {
|
||||
/* Left, right, bottom, top. */
|
||||
timeline_ctx->quads->add_quad(x0 - dx, y0, x0 + dx, y1, col);
|
||||
timeline_ctx->quads->add_quad(x1 - dx, y0, x1 + dx, y1, col);
|
||||
timeline_ctx->quads->add_quad(x0, y0, x1, y0 + dy * 2, col);
|
||||
timeline_ctx->quads->add_quad(x0, y1 - dy * 2, x1, y1, col);
|
||||
|
||||
/* Inset. */
|
||||
UI_GetThemeColor3ubv(TH_BACK, col);
|
||||
timeline_ctx->quads->add_quad(x0 + dx, y0 + dy * 2, x0 + dx * 2, y1 - dy * 2, col);
|
||||
timeline_ctx->quads->add_quad(x1 - dx * 2, y0 + dy * 2, x1 - dx, y1 - dy * 2, col);
|
||||
timeline_ctx->quads->add_quad(x0 + dx, y0 + dy * 2, x1 - dx, y0 + dy * 3, col);
|
||||
timeline_ctx->quads->add_quad(x0 + dx, y1 - dy * 3, x1 - dx, y1 - dy * 2, col);
|
||||
}
|
||||
else if (active) {
|
||||
/* A subtle highlight outline when active but not selected. */
|
||||
UI_GetThemeColorShade3ubv(TH_SEQ_ACTIVE, -40, col);
|
||||
timeline_ctx->quads->add_wire_quad(x0 + dx, y0, x1 - dx, y1, col);
|
||||
}
|
||||
else {
|
||||
/* Thin wireframe outline for unselected strips. */
|
||||
timeline_ctx->quads->add_wire_quad(x0, y0, x1, y1, col);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *draw_seq_text_get_name(const Sequence *seq)
|
||||
{
|
||||
const char *name = seq->name + 2;
|
||||
@@ -1030,9 +922,8 @@ static void draw_icon_centered(TimelineDrawContext &ctx,
|
||||
}
|
||||
|
||||
static void draw_strip_icons(TimelineDrawContext *timeline_ctx,
|
||||
const blender::Vector<StripDrawContext> &strips)
|
||||
const Vector<StripDrawContext> &strips)
|
||||
{
|
||||
timeline_ctx->quads->draw();
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
|
||||
UI_icon_draw_cache_begin();
|
||||
@@ -1207,183 +1098,6 @@ static uchar mute_alpha_factor_get(const ListBase *channels, const Sequence *seq
|
||||
return 255;
|
||||
}
|
||||
|
||||
static void draw_strip_color_band(TimelineDrawContext *timeline_ctx,
|
||||
const StripDrawContext *strip_ctx)
|
||||
{
|
||||
const Sequence *seq = strip_ctx->seq;
|
||||
if ((timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) == 0 || (seq->type != SEQ_TYPE_COLOR)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SolidColorVars *colvars = (SolidColorVars *)seq->effectdata;
|
||||
uchar col[4];
|
||||
rgb_float_to_uchar(col, colvars->col);
|
||||
col[3] = mute_alpha_factor_get(timeline_ctx->channels, seq);
|
||||
|
||||
timeline_ctx->quads->add_quad(strip_ctx->left_handle,
|
||||
strip_ctx->bottom,
|
||||
strip_ctx->right_handle,
|
||||
strip_ctx->strip_content_top,
|
||||
col);
|
||||
|
||||
/* 1px line to better separate the color band. */
|
||||
UI_GetColorPtrShade3ubv(col, col, -20);
|
||||
timeline_ctx->quads->add_line(strip_ctx->left_handle,
|
||||
strip_ctx->strip_content_top,
|
||||
strip_ctx->right_handle,
|
||||
strip_ctx->strip_content_top,
|
||||
col);
|
||||
}
|
||||
|
||||
static void draw_strip_background(TimelineDrawContext *timeline_ctx,
|
||||
const StripDrawContext *strip_ctx)
|
||||
{
|
||||
const Scene *scene = timeline_ctx->scene;
|
||||
const Sequence *seq = strip_ctx->seq;
|
||||
|
||||
uchar col[4];
|
||||
color3ubv_from_seq(scene, seq, strip_ctx->show_strip_color_tag, col);
|
||||
col[3] = mute_alpha_factor_get(timeline_ctx->channels, seq);
|
||||
/* Muted strips: turn almost gray. */
|
||||
if (col[3] == MUTE_ALPHA) {
|
||||
uchar muted_color[3] = {128, 128, 128};
|
||||
UI_GetColorPtrBlendShade3ubv(col, muted_color, col, 0.8f, 0);
|
||||
}
|
||||
|
||||
/* Draw the main strip body. */
|
||||
float x1 = strip_ctx->is_single_image ? strip_ctx->left_handle : strip_ctx->content_start;
|
||||
float x2 = strip_ctx->is_single_image ? strip_ctx->right_handle : strip_ctx->content_end;
|
||||
timeline_ctx->quads->add_quad(x1, strip_ctx->bottom, x2, strip_ctx->top, col);
|
||||
|
||||
/* Draw background for hold still regions. */
|
||||
if (!strip_ctx->is_single_image) {
|
||||
UI_GetColorPtrShade3ubv(col, col, -35);
|
||||
if (SEQ_time_has_left_still_frames(scene, seq)) {
|
||||
timeline_ctx->quads->add_quad(strip_ctx->left_handle,
|
||||
strip_ctx->bottom,
|
||||
strip_ctx->content_start,
|
||||
strip_ctx->top,
|
||||
col);
|
||||
}
|
||||
if (SEQ_time_has_right_still_frames(scene, seq)) {
|
||||
timeline_ctx->quads->add_quad(
|
||||
strip_ctx->content_end, strip_ctx->bottom, strip_ctx->right_handle, strip_ctx->top, col);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum TransitionType {
|
||||
STRIP_TRANSITION_IN,
|
||||
STRIP_TRANSITION_OUT,
|
||||
};
|
||||
|
||||
static void draw_seq_transition_strip_half(TimelineDrawContext *timeline_ctx,
|
||||
const StripDrawContext *strip_ctx,
|
||||
const TransitionType transition_type)
|
||||
{
|
||||
|
||||
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;
|
||||
|
||||
uchar col[4];
|
||||
if (target_seq->type == SEQ_TYPE_COLOR) {
|
||||
SolidColorVars *colvars = (SolidColorVars *)target_seq->effectdata;
|
||||
rgb_float_to_uchar(col, colvars->col);
|
||||
}
|
||||
else {
|
||||
color3ubv_from_seq(timeline_ctx->scene, target_seq, strip_ctx->show_strip_color_tag, col);
|
||||
/* 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(col, col, -15);
|
||||
}
|
||||
}
|
||||
|
||||
col[3] = mute_alpha_factor_get(timeline_ctx->channels, strip_ctx->seq);
|
||||
|
||||
float tri[3][2];
|
||||
|
||||
if (transition_type == STRIP_TRANSITION_IN) {
|
||||
copy_v2_fl2(tri[0], strip_ctx->content_start, strip_ctx->bottom);
|
||||
copy_v2_fl2(tri[1], strip_ctx->content_start, strip_ctx->strip_content_top);
|
||||
copy_v2_fl2(tri[2], strip_ctx->content_end, strip_ctx->bottom);
|
||||
}
|
||||
else {
|
||||
copy_v2_fl2(tri[0], strip_ctx->content_start, strip_ctx->strip_content_top);
|
||||
copy_v2_fl2(tri[1], strip_ctx->content_end, strip_ctx->strip_content_top);
|
||||
copy_v2_fl2(tri[2], strip_ctx->content_end, strip_ctx->bottom);
|
||||
}
|
||||
|
||||
/* Slightly suboptimal: we are pretending to draw a quad with two vertices at the same location.
|
||||
*/
|
||||
timeline_ctx->quads->add_quad(
|
||||
tri[0][0], tri[0][1], tri[0][0], tri[0][1], tri[1][0], tri[1][1], tri[2][0], tri[2][1], col);
|
||||
}
|
||||
|
||||
static void draw_seq_transition_strip(TimelineDrawContext *timeline_ctx,
|
||||
const StripDrawContext *strip_ctx)
|
||||
{
|
||||
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(TimelineDrawContext *timeline_ctx,
|
||||
const blender::Vector<StripDrawContext> &strips)
|
||||
{
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
|
||||
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
|
||||
immBindBuiltinProgram(GPU_SHADER_2D_DIAG_STRIPES);
|
||||
|
||||
immUniform4f("color1", 1.0f, 1.0f, 1.0f, 0.0f);
|
||||
immUniform4f("color2", 0.0f, 0.0f, 0.0f, 0.25f);
|
||||
immUniform1i("size1", 8);
|
||||
immUniform1i("size2", 4);
|
||||
|
||||
for (const StripDrawContext &strip : strips) {
|
||||
if (!SEQ_transform_is_locked(timeline_ctx->channels, strip.seq)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
immRectf(pos, strip.left_handle, strip.bottom, strip.right_handle, strip.strip_content_top);
|
||||
}
|
||||
|
||||
immUnbindProgram();
|
||||
|
||||
GPU_blend(GPU_BLEND_NONE);
|
||||
}
|
||||
|
||||
static void draw_seq_missing(TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx)
|
||||
{
|
||||
if (!strip_ctx->missing_data_block && !strip_ctx->missing_media) {
|
||||
return;
|
||||
}
|
||||
/* Do not tint title area for muted strips; we want to see gray for them. */
|
||||
if (!SEQ_render_is_muted(timeline_ctx->channels, strip_ctx->seq)) {
|
||||
uchar col_top[4] = {112, 0, 0, 230};
|
||||
timeline_ctx->quads->add_quad(strip_ctx->left_handle,
|
||||
strip_ctx->top,
|
||||
strip_ctx->right_handle,
|
||||
strip_ctx->strip_content_top,
|
||||
col_top);
|
||||
}
|
||||
/* Do not tint content area for meta strips; we want to display children. */
|
||||
if (strip_ctx->seq->type != SEQ_TYPE_META) {
|
||||
uchar col_main[4] = {64, 0, 0, 230};
|
||||
timeline_ctx->quads->add_quad(strip_ctx->left_handle,
|
||||
strip_ctx->strip_content_top,
|
||||
strip_ctx->right_handle,
|
||||
strip_ctx->bottom,
|
||||
col_main);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw f-curves as darkened regions of the strip:
|
||||
* - Volume for sound strips.
|
||||
@@ -1493,38 +1207,6 @@ static void draw_multicam_highlight(TimelineDrawContext *timeline_ctx,
|
||||
timeline_ctx->quads->add_quad(v2d->cur.xmin, channel, v2d->cur.xmax, channel + 1, color);
|
||||
}
|
||||
|
||||
/* Highlight strip if it is input of selected active strip. */
|
||||
static void draw_effect_inputs_highlight(TimelineDrawContext *timeline_ctx,
|
||||
const StripDrawContext *strip_ctx)
|
||||
{
|
||||
Sequence *act_seq = SEQ_select_active_get(timeline_ctx->scene);
|
||||
|
||||
if (act_seq == nullptr || (act_seq->flag & SELECT) == 0) {
|
||||
return;
|
||||
}
|
||||
if (act_seq->seq1 != strip_ctx->seq && act_seq->seq2 != strip_ctx->seq) {
|
||||
return;
|
||||
}
|
||||
|
||||
uchar color[4] = {255, 255, 255, 48};
|
||||
timeline_ctx->quads->add_quad(
|
||||
strip_ctx->left_handle, strip_ctx->bottom, strip_ctx->right_handle, strip_ctx->top, color);
|
||||
}
|
||||
|
||||
static void draw_seq_solo_highlight(TimelineDrawContext *timeline_ctx,
|
||||
const StripDrawContext *strip_ctx)
|
||||
{
|
||||
if (ED_sequencer_special_preview_get() == nullptr ||
|
||||
ED_sequencer_special_preview_get() != strip_ctx->seq)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uchar color[4] = {255, 255, 255, 48};
|
||||
timeline_ctx->quads->add_quad(
|
||||
strip_ctx->left_handle, strip_ctx->bottom, strip_ctx->right_handle, strip_ctx->top, color);
|
||||
}
|
||||
|
||||
/* Force redraw, when prefetching and using cache view. */
|
||||
static void seq_prefetch_wm_notify(const bContext *C, Scene *scene)
|
||||
{
|
||||
@@ -1560,11 +1242,11 @@ static void draw_seq_timeline_channels(TimelineDrawContext *ctx)
|
||||
* sure that visually selected are always "on top" of others. It matters
|
||||
* while selection is being dragged over other strips. */
|
||||
static void visible_strips_ordered_get(TimelineDrawContext *timeline_ctx,
|
||||
blender::Vector<StripDrawContext> &r_unselected,
|
||||
blender::Vector<StripDrawContext> &r_selected)
|
||||
Vector<StripDrawContext> &r_unselected,
|
||||
Vector<StripDrawContext> &r_selected)
|
||||
{
|
||||
Sequence *act_seq = SEQ_select_active_get(timeline_ctx->scene);
|
||||
blender::Vector<Sequence *> strips = sequencer_visible_strips_get(timeline_ctx->C);
|
||||
Vector<Sequence *> strips = sequencer_visible_strips_get(timeline_ctx->C);
|
||||
r_unselected.clear();
|
||||
r_selected.clear();
|
||||
const bool act_seq_is_selected = act_seq != nullptr && (act_seq->flag & SELECT) != 0;
|
||||
@@ -1594,8 +1276,294 @@ 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<SeqStripDrawData> 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,
|
||||
const Vector<StripDrawContext> &strips)
|
||||
{
|
||||
GPU_blend(GPU_BLEND_ALPHA_PREMULT);
|
||||
|
||||
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;
|
||||
|
||||
/* Background color. */
|
||||
uchar col[4];
|
||||
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. */
|
||||
if (col[3] == MUTE_ALPHA) {
|
||||
uchar muted_color[3] = {128, 128, 128};
|
||||
UI_GetColorPtrBlendShade3ubv(col, muted_color, col, 0.8f, 0);
|
||||
}
|
||||
data.col_background = color_pack(col);
|
||||
|
||||
/* Color band state. */
|
||||
if (show_overlay && (strip.seq->type == SEQ_TYPE_COLOR)) {
|
||||
data.flags |= GPU_SEQ_FLAG_COLOR_BAND;
|
||||
SolidColorVars *colvars = (SolidColorVars *)strip.seq->effectdata;
|
||||
rgb_float_to_uchar(col, colvars->col);
|
||||
data.col_color_band = color_pack(col);
|
||||
}
|
||||
|
||||
/* Transition state. */
|
||||
if (show_overlay && strip.can_draw_strip_content &&
|
||||
ELEM(strip.seq->type, SEQ_TYPE_CROSS, SEQ_TYPE_GAMCROSS, SEQ_TYPE_WIPE))
|
||||
{
|
||||
data.flags |= GPU_SEQ_FLAG_TRANSITION;
|
||||
|
||||
const Sequence *seq1 = strip.seq->seq1;
|
||||
const Sequence *seq2 = strip.seq->seq2;
|
||||
|
||||
/* Left side. */
|
||||
if (seq1->type == SEQ_TYPE_COLOR) {
|
||||
rgb_float_to_uchar(col, ((const SolidColorVars *)seq1->effectdata)->col);
|
||||
}
|
||||
else {
|
||||
color3ubv_from_seq(scene, seq1, strip.show_strip_color_tag, col);
|
||||
}
|
||||
data.col_transition_in = color_pack(col);
|
||||
|
||||
/* Right side. */
|
||||
if (seq2->type == SEQ_TYPE_COLOR) {
|
||||
rgb_float_to_uchar(col, ((const SolidColorVars *)seq2->effectdata)->col);
|
||||
}
|
||||
else {
|
||||
color3ubv_from_seq(scene, seq2, strip.show_strip_color_tag, col);
|
||||
/* If the transition inputs are of the same type, draw the right side slightly darker. */
|
||||
if (seq1->type == seq2->type) {
|
||||
UI_GetColorPtrShade3ubv(col, col, -15);
|
||||
}
|
||||
}
|
||||
data.col_transition_out = color_pack(col);
|
||||
}
|
||||
}
|
||||
strips_batch.flush_batch();
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
}
|
||||
|
||||
static void draw_strips_foreground(TimelineDrawContext *timeline_ctx,
|
||||
SeqStripsBatch &strips_batch,
|
||||
const Vector<StripDrawContext> &strips)
|
||||
{
|
||||
GPU_blend(GPU_BLEND_ALPHA_PREMULT);
|
||||
const Scene *scene = timeline_ctx->scene;
|
||||
const Sequence *act_seq = SEQ_select_active_get(scene);
|
||||
const Sequence *special_preview = ED_sequencer_special_preview_get();
|
||||
const bool show_handles = (U.sequencer_editor_flag & USER_SEQ_ED_SIMPLE_TWEAKING) == 0;
|
||||
|
||||
uchar col[4];
|
||||
for (const StripDrawContext &strip : strips) {
|
||||
SeqStripDrawData &data = strips_batch.add_strip(strip);
|
||||
|
||||
/* Missing media state. */
|
||||
if (strip.missing_data_block || strip.missing_media) {
|
||||
/* Do not tint title area for muted strips; we want to see gray for them. */
|
||||
if (!SEQ_render_is_muted(timeline_ctx->channels, strip.seq)) {
|
||||
data.flags |= GPU_SEQ_FLAG_MISSING_TITLE;
|
||||
}
|
||||
/* Do not tint content area for meta strips; we want to display children. */
|
||||
if (strip.seq->type != SEQ_TYPE_META) {
|
||||
data.flags |= GPU_SEQ_FLAG_MISSING_CONTENT;
|
||||
}
|
||||
}
|
||||
|
||||
/* Locked state. */
|
||||
const bool locked = SEQ_transform_is_locked(timeline_ctx->channels, strip.seq);
|
||||
if (locked) {
|
||||
data.flags |= GPU_SEQ_FLAG_LOCKED;
|
||||
}
|
||||
|
||||
/* Border and outline. */
|
||||
const bool selected = strip.seq->flag & SELECT;
|
||||
const bool active = strip.is_active_strip;
|
||||
if (selected) {
|
||||
UI_GetThemeColor3ubv(active ? TH_SEQ_ACTIVE : TH_SEQ_SELECTED, col);
|
||||
}
|
||||
else {
|
||||
/* Color for unselected strips is a bit darker than the background. */
|
||||
UI_GetThemeColorShade3ubv(TH_BACK, -40, col);
|
||||
}
|
||||
col[3] = 255;
|
||||
/* Outline while translating strips:
|
||||
* - Slightly lighter.
|
||||
* - Red when overlapping with other strips. */
|
||||
const eSeqOverlapMode overlap_mode = SEQ_tool_settings_overlap_mode_get(timeline_ctx->scene);
|
||||
if ((G.moving & G_TRANSFORM_SEQ) && selected && overlap_mode != SEQ_OVERLAP_OVERWRITE) {
|
||||
if (strip.seq->flag & SEQ_OVERLAP) {
|
||||
col[0] = 255;
|
||||
col[1] = col[2] = 33;
|
||||
}
|
||||
else {
|
||||
UI_GetColorPtrShade3ubv(col, col, 70);
|
||||
}
|
||||
}
|
||||
if (selected)
|
||||
data.flags |= GPU_SEQ_FLAG_SELECTED;
|
||||
else if (active) {
|
||||
/* A subtle highlight outline when active but not selected. */
|
||||
UI_GetThemeColorShade3ubv(TH_SEQ_ACTIVE, -40, col);
|
||||
data.flags |= GPU_SEQ_FLAG_ACTIVE;
|
||||
}
|
||||
data.col_outline = color_pack(col);
|
||||
|
||||
/* Highlight if strip is an input of an active strip, or if the strip is solo preview. */
|
||||
if (act_seq != nullptr && (act_seq->flag & SELECT) != 0) {
|
||||
if (act_seq->seq1 == strip.seq || act_seq->seq2 == strip.seq) {
|
||||
data.flags |= GPU_SEQ_FLAG_HIGHLIGHT;
|
||||
}
|
||||
}
|
||||
if (special_preview == strip.seq) {
|
||||
data.flags |= GPU_SEQ_FLAG_HIGHLIGHT;
|
||||
}
|
||||
|
||||
/* Handles on left/right side. */
|
||||
if (!locked && ED_sequencer_can_select_handle(scene, strip.seq, timeline_ctx->v2d)) {
|
||||
data.flags |= GPU_SEQ_FLAG_HANDLES;
|
||||
const bool selected_l = ED_sequencer_handle_is_selected(strip.seq, SEQ_HANDLE_LEFT);
|
||||
const bool selected_r = ED_sequencer_handle_is_selected(strip.seq, SEQ_HANDLE_RIGHT);
|
||||
const bool show_l = show_handles || (selected && selected_l);
|
||||
const bool show_r = show_handles || (selected && selected_r);
|
||||
|
||||
/* Left handle color. */
|
||||
col[0] = col[1] = col[2] = 0;
|
||||
col[3] = 50;
|
||||
if (selected && selected_l) {
|
||||
UI_GetThemeColor4ubv(active ? TH_SEQ_ACTIVE : TH_SEQ_SELECTED, col);
|
||||
}
|
||||
if (!show_l) {
|
||||
col[3] = 0;
|
||||
}
|
||||
data.col_handle_left = color_pack(col);
|
||||
|
||||
/* Right handle color. */
|
||||
col[0] = col[1] = col[2] = 0;
|
||||
col[3] = 50;
|
||||
if (selected && selected_r) {
|
||||
UI_GetThemeColor4ubv(active ? TH_SEQ_ACTIVE : TH_SEQ_SELECTED, col);
|
||||
}
|
||||
if (!show_r) {
|
||||
col[3] = 0;
|
||||
}
|
||||
data.col_handle_right = color_pack(col);
|
||||
}
|
||||
}
|
||||
strips_batch.flush_batch();
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
}
|
||||
|
||||
static void draw_seq_strips(TimelineDrawContext *timeline_ctx,
|
||||
const blender::Vector<StripDrawContext> &strips)
|
||||
SeqStripsBatch &strips_batch,
|
||||
const Vector<StripDrawContext> &strips)
|
||||
{
|
||||
if (strips.is_empty()) {
|
||||
return;
|
||||
@@ -1605,17 +1573,17 @@ static void draw_seq_strips(TimelineDrawContext *timeline_ctx,
|
||||
|
||||
/* Draw parts of strips below thumbnails. */
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
draw_strips_background(timeline_ctx, strips_batch, strips);
|
||||
|
||||
const float round_radius = calc_strip_round_radius(timeline_ctx->pixely);
|
||||
for (const StripDrawContext &strip_ctx : strips) {
|
||||
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);
|
||||
drawmeta_contents(timeline_ctx, &strip_ctx, round_radius);
|
||||
}
|
||||
timeline_ctx->quads->draw();
|
||||
GPU_blend(GPU_BLEND_NONE);
|
||||
|
||||
/* Draw all thumbnails. */
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
for (const StripDrawContext &strip_ctx : strips) {
|
||||
draw_seq_strip_thumbnail(timeline_ctx->v2d,
|
||||
timeline_ctx->C,
|
||||
@@ -1623,8 +1591,10 @@ static void draw_seq_strips(TimelineDrawContext *timeline_ctx,
|
||||
strip_ctx.seq,
|
||||
strip_ctx.bottom,
|
||||
strip_ctx.strip_content_top,
|
||||
strip_ctx.top,
|
||||
timeline_ctx->pixelx,
|
||||
timeline_ctx->pixely);
|
||||
timeline_ctx->pixely,
|
||||
round_radius);
|
||||
}
|
||||
|
||||
/* Draw parts of strips above thumbnails. */
|
||||
@@ -1632,53 +1602,38 @@ static void draw_seq_strips(TimelineDrawContext *timeline_ctx,
|
||||
for (const StripDrawContext &strip_ctx : strips) {
|
||||
draw_seq_fcurve_overlay(timeline_ctx, &strip_ctx);
|
||||
draw_seq_waveform_overlay(timeline_ctx, &strip_ctx);
|
||||
draw_seq_missing(timeline_ctx, &strip_ctx);
|
||||
}
|
||||
timeline_ctx->quads->draw();
|
||||
GPU_blend(GPU_BLEND_NONE);
|
||||
|
||||
/* Locked state is drawn separately since it uses a different shader. */
|
||||
draw_seq_locked(timeline_ctx, strips);
|
||||
|
||||
/* Draw the rest. */
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
for (const StripDrawContext &strip_ctx : strips) {
|
||||
draw_effect_inputs_highlight(timeline_ctx, &strip_ctx);
|
||||
draw_multicam_highlight(timeline_ctx, &strip_ctx);
|
||||
draw_seq_solo_highlight(timeline_ctx, &strip_ctx);
|
||||
draw_seq_handle(timeline_ctx, &strip_ctx, SEQ_HANDLE_LEFT);
|
||||
draw_seq_handle(timeline_ctx, &strip_ctx, SEQ_HANDLE_RIGHT);
|
||||
draw_handle_transform_text(timeline_ctx, &strip_ctx, SEQ_HANDLE_LEFT);
|
||||
draw_handle_transform_text(timeline_ctx, &strip_ctx, SEQ_HANDLE_RIGHT);
|
||||
draw_seq_outline(timeline_ctx, &strip_ctx);
|
||||
draw_seq_text_overlay(timeline_ctx, &strip_ctx);
|
||||
}
|
||||
|
||||
/* Draw icons separately (different shader). */
|
||||
draw_strip_icons(timeline_ctx, strips);
|
||||
|
||||
timeline_ctx->quads->draw();
|
||||
|
||||
draw_strips_foreground(timeline_ctx, strips_batch, strips);
|
||||
|
||||
/* Draw icons. */
|
||||
draw_strip_icons(timeline_ctx, strips);
|
||||
|
||||
/* Draw text labels with a drop shadow. */
|
||||
const int font_id = BLF_default();
|
||||
BLF_enable(font_id, BLF_SHADOW);
|
||||
BLF_shadow(font_id, FontShadowType::Blur3x3, blender::float4{0.0f, 0.0f, 0.0f, 1.0f});
|
||||
BLF_shadow(font_id, FontShadowType::Blur3x3, float4{0.0f, 0.0f, 0.0f, 1.0f});
|
||||
BLF_shadow_offset(font_id, 1, -1);
|
||||
UI_view2d_text_cache_draw(timeline_ctx->region);
|
||||
BLF_disable(font_id, BLF_SHADOW);
|
||||
GPU_blend(GPU_BLEND_NONE);
|
||||
}
|
||||
|
||||
static void draw_seq_strips(TimelineDrawContext *timeline_ctx)
|
||||
static void draw_seq_strips(TimelineDrawContext *timeline_ctx, SeqStripsBatch &strips_batch)
|
||||
{
|
||||
if (timeline_ctx->ed == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
blender::Vector<StripDrawContext> unselected, selected;
|
||||
Vector<StripDrawContext> unselected, selected;
|
||||
visible_strips_ordered_get(timeline_ctx, unselected, selected);
|
||||
draw_seq_strips(timeline_ctx, unselected);
|
||||
draw_seq_strips(timeline_ctx, selected);
|
||||
draw_seq_strips(timeline_ctx, strips_batch, unselected);
|
||||
draw_seq_strips(timeline_ctx, strips_batch, selected);
|
||||
}
|
||||
|
||||
static void draw_timeline_sfra_efra(TimelineDrawContext *ctx)
|
||||
@@ -1773,7 +1728,6 @@ static bool draw_cache_view_iter_fn(void *userdata,
|
||||
int timeline_frame,
|
||||
int cache_type)
|
||||
{
|
||||
using blender::uchar4;
|
||||
CacheDrawData *drawdata = static_cast<CacheDrawData *>(userdata);
|
||||
const View2D *v2d = drawdata->v2d;
|
||||
float stripe_top, stripe_bot;
|
||||
@@ -1847,7 +1801,6 @@ static void draw_cache_stripe(const Scene *scene,
|
||||
|
||||
static void draw_cache_background(const bContext *C, CacheDrawData *draw_data)
|
||||
{
|
||||
using blender::uchar4;
|
||||
const Scene *scene = CTX_data_scene(C);
|
||||
const View2D *v2d = UI_view2d_fromcontext(C);
|
||||
const SpaceSeq *sseq = CTX_wm_space_seq(C);
|
||||
@@ -1876,7 +1829,7 @@ static void draw_cache_background(const bContext *C, CacheDrawData *draw_data)
|
||||
return;
|
||||
}
|
||||
|
||||
blender::Vector<Sequence *> strips = sequencer_visible_strips_get(C);
|
||||
Vector<Sequence *> strips = sequencer_visible_strips_get(C);
|
||||
strips.remove_if([&](Sequence *seq) { return seq->type == SEQ_TYPE_SOUND_RAM; });
|
||||
|
||||
for (const Sequence *seq : strips) {
|
||||
@@ -2029,6 +1982,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);
|
||||
|
||||
draw_timeline_pre_view_callbacks(&ctx);
|
||||
UI_ThemeClearColor(TH_BACK);
|
||||
@@ -2036,7 +1990,7 @@ void draw_timeline_seq(const bContext *C, ARegion *region)
|
||||
draw_timeline_grid(&ctx);
|
||||
draw_timeline_backdrop(&ctx);
|
||||
draw_timeline_sfra_efra(&ctx);
|
||||
draw_seq_strips(&ctx);
|
||||
draw_seq_strips(&ctx, strips_batch);
|
||||
sequencer_draw_retiming(C, &quads_batch);
|
||||
draw_timeline_markers(&ctx);
|
||||
UI_view2d_view_ortho(ctx.v2d);
|
||||
|
||||
@@ -503,6 +503,9 @@ set(GLSL_SRC
|
||||
shaders/gpu_shader_keyframe_shape_vert.glsl
|
||||
shaders/gpu_shader_keyframe_shape_frag.glsl
|
||||
|
||||
shaders/gpu_shader_sequencer_strips_vert.glsl
|
||||
shaders/gpu_shader_sequencer_strips_frag.glsl
|
||||
|
||||
shaders/gpu_shader_codegen_lib.glsl
|
||||
|
||||
shaders/common/gpu_shader_bicubic_sampler_lib.glsl
|
||||
@@ -788,6 +791,7 @@ set(SRC_SHADER_CREATE_INFOS
|
||||
shaders/infos/gpu_shader_instance_varying_color_varying_size_info.hh
|
||||
shaders/infos/gpu_shader_keyframe_shape_info.hh
|
||||
shaders/infos/gpu_shader_line_dashed_uniform_color_info.hh
|
||||
shaders/infos/gpu_shader_sequencer_info.hh
|
||||
shaders/infos/gpu_shader_simple_lighting_info.hh
|
||||
shaders/infos/gpu_shader_text_info.hh
|
||||
shaders/infos/gpu_srgb_to_framebuffer_space_info.hh
|
||||
|
||||
@@ -75,6 +75,9 @@ enum eGPUBuiltinShader {
|
||||
/** Draw wide lines with uniform color. Has an additional clip plane parameter. */
|
||||
GPU_SHADER_3D_POLYLINE_CLIPPED_UNIFORM_COLOR,
|
||||
|
||||
/** Draw strip widgets in sequencer timeline. */
|
||||
GPU_SHADER_SEQUENCER_STRIPS,
|
||||
|
||||
/** Compute shaders to generate 2d index buffers (mainly for curve drawing). */
|
||||
GPU_SHADER_INDEXBUF_POINTS,
|
||||
GPU_SHADER_INDEXBUF_LINES,
|
||||
|
||||
@@ -90,6 +90,55 @@ struct MultiIconCallData {
|
||||
};
|
||||
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_SINGLE_IMAGE = (1u << 1u),
|
||||
GPU_SEQ_FLAG_COLOR_BAND = (1u << 2u),
|
||||
GPU_SEQ_FLAG_TRANSITION = (1u << 3u),
|
||||
GPU_SEQ_FLAG_LOCKED = (1u << 4u),
|
||||
GPU_SEQ_FLAG_MISSING_TITLE = (1u << 5u),
|
||||
GPU_SEQ_FLAG_MISSING_CONTENT = (1u << 6u),
|
||||
GPU_SEQ_FLAG_SELECTED = (1u << 7u),
|
||||
GPU_SEQ_FLAG_ACTIVE = (1u << 8u),
|
||||
GPU_SEQ_FLAG_HIGHLIGHT = (1u << 9u),
|
||||
GPU_SEQ_FLAG_HANDLES = (1u << 10u),
|
||||
};
|
||||
|
||||
/* VSE per-strip data for timeline rendering. */
|
||||
struct SeqStripDrawData {
|
||||
/* Horizontal strip positions (1.0 is one frame). */
|
||||
float left_handle, right_handle; /* Left and right strip sides. */
|
||||
float content_start, content_end; /* Start and end of actual content (only relevant for strips that have holdout regions). */
|
||||
float handle_width;
|
||||
/* Vertical strip positions (1.0 is one channel). */
|
||||
float bottom;
|
||||
float top;
|
||||
float strip_content_top; /* Content coordinate, i.e. below title bar if there is one. */
|
||||
uint flags; /* eGPUSeqFlags bitmask. */
|
||||
/* Strip colors, each is uchar4 packed with equivalent of packUnorm4x8. */
|
||||
uint col_background;
|
||||
uint col_outline;
|
||||
uint col_color_band;
|
||||
uint col_transition_in, col_transition_out;
|
||||
uint col_handle_left, col_handle_right;
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(SeqStripDrawData, 16)
|
||||
BLI_STATIC_ASSERT(sizeof(SeqStripDrawData) * GPU_SEQ_STRIP_DRAW_DATA_LEN <= 16384,
|
||||
"SeqStripDrawData UBO must not exceed minspec UBO size (16K)")
|
||||
|
||||
/* VSE global data for timeline rendering. */
|
||||
struct SeqContextDrawData {
|
||||
float pixelx, pixely; /* Size of one pixel in timeline coordinate space. */
|
||||
float inv_pixelx, inv_pixely;
|
||||
float round_radius;
|
||||
uint col_back;
|
||||
float _pad0, _pad1;
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(SeqContextDrawData, 16)
|
||||
|
||||
|
||||
enum TestStatus : uint32_t {
|
||||
TEST_STATUS_NONE = 0u,
|
||||
TEST_STATUS_PASSED = 1u,
|
||||
|
||||
@@ -87,6 +87,8 @@ static const char *builtin_shader_create_info_name(eGPUBuiltinShader shader)
|
||||
return "gpu_shader_2D_nodelink_inst";
|
||||
case GPU_SHADER_GPENCIL_STROKE:
|
||||
return "gpu_shader_gpencil_stroke";
|
||||
case GPU_SHADER_SEQUENCER_STRIPS:
|
||||
return "gpu_shader_sequencer_strips";
|
||||
case GPU_SHADER_INDEXBUF_POINTS:
|
||||
return "gpu_shader_index_2d_array_points";
|
||||
case GPU_SHADER_INDEXBUF_LINES:
|
||||
|
||||
161
source/blender/gpu/shaders/gpu_shader_sequencer_strips_frag.glsl
Normal file
161
source/blender/gpu/shaders/gpu_shader_sequencer_strips_frag.glsl
Normal file
@@ -0,0 +1,161 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/* Signed distance to rounded box, centered at origin.
|
||||
* Reference: https://iquilezles.org/articles/distfunctions2d/ */
|
||||
float sdf_rounded_box(vec2 pos, vec2 size, float radius)
|
||||
{
|
||||
vec2 q = abs(pos) - size + radius;
|
||||
return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - radius;
|
||||
}
|
||||
|
||||
vec3 color_shade(vec3 rgb, float shade)
|
||||
{
|
||||
rgb += vec3(shade / 255.0);
|
||||
rgb = clamp(rgb, vec3(0.0), vec3(1.0));
|
||||
return rgb;
|
||||
}
|
||||
|
||||
/* Blends in a straight alpha `color` into premultiplied `cur` and returns premultiplied result. */
|
||||
vec4 blend_color(vec4 cur, vec4 color)
|
||||
{
|
||||
float t = color.a;
|
||||
return cur * (1.0 - t) + vec4(color.rgb * t, t);
|
||||
}
|
||||
|
||||
/* Given signed distance `d` to a shape and current premultiplied color `cur`, blends
|
||||
* in an outline of at least 1px width (plus `extra_half_width` on each side), inset
|
||||
* by `inset` pixels. Outline color `outline_color` is in straight alpha. */
|
||||
vec4 add_outline(float d, float extra_half_width, float inset, vec4 cur, vec4 outline_color)
|
||||
{
|
||||
float f = abs(d + inset) - extra_half_width;
|
||||
float a = clamp(1.0 - f, 0.0, 1.0);
|
||||
outline_color.a *= a;
|
||||
return blend_color(cur, outline_color);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 co = co_interp;
|
||||
|
||||
SeqStripDrawData strip = strip_data[strip_id];
|
||||
vec2 size = vec2(strip.right_handle - strip.left_handle, strip.top - strip.bottom) * 0.5;
|
||||
vec2 center = vec2(strip.right_handle + strip.left_handle, strip.top + strip.bottom) * 0.5;
|
||||
|
||||
/* Transform strip rectangle into pixel coordinates, so that
|
||||
* rounded corners have proper aspect ratio and can be expressed in pixels. */
|
||||
vec2 view_to_pixel = vec2(context_data.inv_pixelx, context_data.inv_pixely);
|
||||
size *= view_to_pixel;
|
||||
center *= view_to_pixel;
|
||||
vec2 pos = co * view_to_pixel;
|
||||
|
||||
float radius = context_data.round_radius;
|
||||
if (radius > size.x) {
|
||||
radius = 0.0;
|
||||
}
|
||||
|
||||
float sdf = sdf_rounded_box(pos - center, size, radius);
|
||||
|
||||
vec4 col = vec4(0.0);
|
||||
|
||||
bool back_part = (strip.flags & GPU_SEQ_FLAG_BACKGROUND_PART) != 0;
|
||||
|
||||
if (back_part) {
|
||||
|
||||
col = unpackUnorm4x8(strip.col_background);
|
||||
/* Darker background for multi-image strip hold still regions. */
|
||||
if ((strip.flags & GPU_SEQ_FLAG_SINGLE_IMAGE) == 0) {
|
||||
if (co.x < strip.content_start || co.x > strip.content_end) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 rect? */
|
||||
if (sdf > 0.0) {
|
||||
col = vec4(0.0);
|
||||
}
|
||||
|
||||
/* Outline. */
|
||||
if (!back_part) {
|
||||
bool selected = (strip.flags & GPU_SEQ_FLAG_SELECTED) != 0;
|
||||
vec4 col_outline = unpackUnorm4x8(strip.col_outline);
|
||||
if (selected) {
|
||||
/* Inset 1px line with backround color. */
|
||||
col = add_outline(sdf, 0.0, 1.0, col, unpackUnorm4x8(context_data.col_back));
|
||||
/* 2x wide outline. */
|
||||
col = add_outline(sdf, 0.5, -0.5, col, col_outline);
|
||||
}
|
||||
else {
|
||||
col = add_outline(sdf, 0.0, 0.0, col, col_outline);
|
||||
}
|
||||
}
|
||||
|
||||
fragColor = col;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
void main()
|
||||
{
|
||||
int id = gl_InstanceID;
|
||||
strip_id = id;
|
||||
int vid = gl_VertexID;
|
||||
SeqStripDrawData strip = strip_data[id];
|
||||
vec4 rect = vec4(strip.left_handle, strip.bottom, strip.right_handle, strip.top);
|
||||
/* Expand rasterized rectangle by 1px so that we can do outlines. */
|
||||
rect.x -= context_data.pixelx;
|
||||
rect.z += context_data.pixelx;
|
||||
rect.y -= context_data.pixely;
|
||||
rect.w += context_data.pixely;
|
||||
|
||||
vec2 co;
|
||||
if (vid == 0) {
|
||||
co = rect.xw;
|
||||
}
|
||||
else if (vid == 1) {
|
||||
co = rect.xy;
|
||||
}
|
||||
else if (vid == 2) {
|
||||
co = rect.zw;
|
||||
}
|
||||
else {
|
||||
co = rect.zy;
|
||||
}
|
||||
|
||||
co_interp = co;
|
||||
gl_Position = ModelViewProjectionMatrix * vec4(co, 0.0f, 1.0f);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*/
|
||||
|
||||
#include "gpu_interface_info.hh"
|
||||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
GPU_SHADER_INTERFACE_INFO(gpu_seq_strip_iface, "")
|
||||
.no_perspective(Type::VEC2, "co_interp")
|
||||
.flat(Type::UINT, "strip_id");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(gpu_shader_sequencer_strips)
|
||||
.vertex_out(gpu_seq_strip_iface)
|
||||
.fragment_out(0, Type::VEC4, "fragColor")
|
||||
.push_constant(Type::MAT4, "ModelViewProjectionMatrix")
|
||||
.uniform_buf(0, "SeqStripDrawData", "strip_data[GPU_SEQ_STRIP_DRAW_DATA_LEN]")
|
||||
.uniform_buf(1, "SeqContextDrawData", "context_data")
|
||||
.typedef_source("GPU_shader_shared.hh")
|
||||
.vertex_source("gpu_shader_sequencer_strips_vert.glsl")
|
||||
.fragment_source("gpu_shader_sequencer_strips_frag.glsl")
|
||||
.do_static_compilation(true);
|
||||
@@ -2091,6 +2091,11 @@ template<typename T> int findMSB(T x)
|
||||
return int(sizeof(T) * 8) - 1 - int(clz(x));
|
||||
}
|
||||
|
||||
#define unpackUnorm4x8 unpack_unorm4x8_to_float
|
||||
#define unpackSnorm4x8 unpack_snorm4x8_to_float
|
||||
#define unpackUnorm2x16 unpack_unorm2x16_to_float
|
||||
#define unpackSnorm2x16 unpack_snorm2x16_to_float
|
||||
|
||||
/* Texture size functions. Add texture types as needed. */
|
||||
#define imageSize(image) textureSize(image, 0)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user