VSE: Scopes improvements #116798

Merged
Aras Pranckevicius merged 13 commits from aras_p/blender:vse-scopes into main 2024-01-05 22:03:13 +01:00
4 changed files with 141 additions and 95 deletions
Showing only changes of commit 6767dc2b39 - Show all commits

View File

@ -10,6 +10,7 @@
#include <cstring>
#include "BLI_blenlib.h"
#include "BLI_math_rotation.h"
#include "BLI_utildefines.h"
#include "IMB_imbuf_types.h"
@ -571,20 +572,98 @@ static void draw_histogram(const blender::ed::seq::ScopeHistogram &hist,
GPU_blend(GPU_BLEND_ALPHA);
}
static blender::float2 rgb_to_uv(const blender::float3 &rgb)
{
float y, u, v;
rgb_to_yuv(rgb.x, rgb.y, rgb.z, &y, &u, &v, BLI_YUV_ITU_BT709);
return blender::float2(u, v);
}
static void draw_vectorscope_graticule(SeqQuadsBatch &quads, const rctf &area)
{
using namespace blender;
GPU_blend(GPU_BLEND_ALPHA);
const float skin_rad = DEG2RADF(123.0f); /* angle in radians of the skin tone line */
const float w = BLI_rctf_size_x(&area);
const float h = BLI_rctf_size_y(&area);
const float centerx = BLI_rctf_cent_x(&area);
const float centery = BLI_rctf_cent_y(&area);
const float radius = ((w < h) ? w : h) * 0.5f * (0.5f / 0.615f);
/* center cross */
uchar col_grid[4] = {128, 128, 128, 96};
quads.add_line(centerx - radius * 0.1f, centery, centerx + radius * 0.1f, centery, col_grid);
quads.add_line(centerx, centery - radius * 0.1f, centerx, centery + radius * 0.1f, col_grid);
/* fully saturated vs "safe" (0.75) colored areas */
quads.draw();
GPU_blend(GPU_BLEND_ADDITIVE);
const float3 primaries[6] = {
{1, 0, 0},
{1, 1, 0},
{0, 1, 0},
{0, 1, 1},
{0, 0, 1},
{1, 0, 1},
};
float2 center{centerx, centery};
for (int i = 0; i < 6; i++) {
float3 prim0 = primaries[i];
float3 prim1 = primaries[(i + 1) % 6];
float3 safe0 = prim0 * 0.75f;
float3 safe1 = prim1 * 0.75f;
float2 uv0 = center + rgb_to_uv(prim0) * (radius * 2);
float2 uv1 = center + rgb_to_uv(prim1) * (radius * 2);
float2 uv2 = center + rgb_to_uv(safe0) * (radius * 2);
aras_p marked this conversation as resolved
Review

Use BLI_snprintf()

Use `BLI_snprintf()`
float2 uv3 = center + rgb_to_uv(safe1) * (radius * 2);
uchar col0[4] = {uchar(prim0.x * 255), uchar(prim0.y * 255), uchar(prim0.z * 255), 128};
uchar col1[4] = {uchar(prim1.x * 255), uchar(prim1.y * 255), uchar(prim1.z * 255), 128};
uchar col2[4] = {uchar(safe0.x * 255), uchar(safe0.y * 255), uchar(safe0.z * 255), 128};
uchar col3[4] = {uchar(safe1.x * 255), uchar(safe1.y * 255), uchar(safe1.z * 255), 128};
quads.add_quad(uv0.x, uv0.y, uv1.x, uv1.y, uv2.x, uv2.y, uv3.x, uv3.y, col0, col1, col2, col3);
}
quads.draw();
GPU_blend(GPU_BLEND_ALPHA);
/* skin tone line */
uchar col_tone[4] = {255, 102, 0, 128};
const float tone_line_len = radius * 0.895f; /* makes it end at outer edge of saturation ring */
quads.add_line(centerx,
centery,
centerx + cosf(skin_rad) * tone_line_len,
centery + sinf(skin_rad) * tone_line_len,
col_tone);
}
static void sequencer_draw_scopes(Scene *scene, ARegion *region, SpaceSeq *sseq, bool draw_overlay)
{
using namespace blender::ed::seq;
/* Figure out draw coordinates. */
rctf preview;
rctf canvas;
sequencer_preview_get_rect(&preview, scene, region, sseq, draw_overlay, false);
rctf uv;
if (draw_overlay && (sseq->overlay_frame_type == SEQ_OVERLAY_FRAME_TYPE_RECT)) {
canvas = scene->ed->overlay_frame_rect;
uv = scene->ed->overlay_frame_rect;
}
else {
BLI_rctf_init(&canvas, 0.0f, 1.0f, 0.0f, 1.0f);
BLI_rctf_init(&uv, 0.0f, 1.0f, 0.0f, 1.0f);
}
const bool keep_aspect = sseq->mainb == SEQ_DRAW_IMG_VECTORSCOPE;
float vecscope_aspect = 1.0f;
if (keep_aspect) {
float width = std::max(BLI_rctf_size_x(&preview), 0.1f);
float height = std::max(BLI_rctf_size_y(&preview), 0.1f);
vecscope_aspect = width / height;
if (vecscope_aspect >= 1.0f) {
BLI_rctf_resize_x(&uv, BLI_rctf_size_x(&uv) * vecscope_aspect);
}
else {
BLI_rctf_resize_y(&uv, BLI_rctf_size_y(&uv) / vecscope_aspect);
}
}
SeqQuadsBatch quads;
@ -623,6 +702,7 @@ static void sequencer_draw_scopes(Scene *scene, ARegion *region, SpaceSeq *sseq,
"seq_display_buf", scope_image->x, scope_image->y, 1, format, usage, nullptr);
GPU_texture_update(texture, data, scope_image->byte_buffer.data);
GPU_texture_filter_mode(texture, false);
GPU_texture_extend_mode(texture, GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER);
GPU_texture_bind(texture, 0);
@ -635,16 +715,16 @@ static void sequencer_draw_scopes(Scene *scene, ARegion *region, SpaceSeq *sseq,
immBegin(GPU_PRIM_TRI_FAN, 4);
immAttr2f(texCoord, canvas.xmin, canvas.ymin);
immAttr2f(texCoord, uv.xmin, uv.ymin);
immVertex2f(pos, preview.xmin, preview.ymin);
immAttr2f(texCoord, canvas.xmin, canvas.ymax);
immAttr2f(texCoord, uv.xmin, uv.ymax);
immVertex2f(pos, preview.xmin, preview.ymax);
immAttr2f(texCoord, canvas.xmax, canvas.ymax);
immAttr2f(texCoord, uv.xmax, uv.ymax);
immVertex2f(pos, preview.xmax, preview.ymax);
immAttr2f(texCoord, canvas.xmax, canvas.ymin);
immAttr2f(texCoord, uv.xmax, uv.ymin);
immVertex2f(pos, preview.xmax, preview.ymin);
immEnd();
@ -673,6 +753,10 @@ static void sequencer_draw_scopes(Scene *scene, ARegion *region, SpaceSeq *sseq,
uchar col_border[4] = {64, 64, 64, 128};
quads.add_wire_quad(x0, preview.ymin, x1, preview.ymax, col_border);
}
if (sseq->mainb == SEQ_DRAW_IMG_VECTORSCOPE) {
use_blend = true;
draw_vectorscope_graticule(quads, preview);
}
quads.draw();

View File

@ -53,10 +53,10 @@ SeqQuadsBatch::SeqQuadsBatch()
batch_quads = GPU_batch_create_ex(
GPU_PRIM_TRIS, vbo_quads, ibo_quads, GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX);
GPU_batch_program_set_builtin(batch_quads, GPU_SHADER_3D_FLAT_COLOR);
GPU_batch_program_set_builtin(batch_quads, GPU_SHADER_3D_SMOOTH_COLOR);
batch_lines = GPU_batch_create_ex(GPU_PRIM_LINES, vbo_lines, nullptr, GPU_BATCH_OWNS_VBO);
GPU_batch_program_set_builtin(batch_lines, GPU_SHADER_3D_FLAT_COLOR);
GPU_batch_program_set_builtin(batch_lines, GPU_SHADER_3D_SMOOTH_COLOR);
}
SeqQuadsBatch::~SeqQuadsBatch()
@ -93,7 +93,10 @@ void SeqQuadsBatch::add_quad(float x1,
float y3,
float x4,
float y4,
const uchar color[4])
const uchar color1[4],
const uchar color2[4],
const uchar color3[4],
const uchar color4[4])
{
if (quads_num >= MAX_QUADS) {
draw();
@ -103,10 +106,10 @@ void SeqQuadsBatch::add_quad(float x1,
BLI_assert(verts_quads != nullptr);
}
ColorVertex v0 = {blender::float2(x1, y1), color};
ColorVertex v1 = {blender::float2(x2, y2), color};
ColorVertex v2 = {blender::float2(x3, y3), color};
ColorVertex v3 = {blender::float2(x4, y4), color};
ColorVertex v0 = {blender::float2(x1, y1), color1};
ColorVertex v1 = {blender::float2(x2, y2), color2};
ColorVertex v2 = {blender::float2(x3, y3), color3};
ColorVertex v3 = {blender::float2(x4, y4), color4};
*verts_quads++ = v0;
*verts_quads++ = v1;

View File

@ -33,9 +33,9 @@ class SeqQuadsBatch {
/** Add an axis-aligned quad. */
void add_quad(float x1, float y1, float x2, float y2, const uchar color[4])
{
add_quad(x1, y1, x1, y2, x2, y1, x2, y2, color);
add_quad(x1, y1, x1, y2, x2, y1, x2, y2, color, color, color, color);
}
/** Add a quad. */
/** Add a quad with four arbitrary coordinates and one color. */
void add_quad(float x1,
float y1,
float x2,
@ -44,7 +44,23 @@ class SeqQuadsBatch {
float y3,
float x4,
float y4,
const uchar color[4]);
const uchar color[4])
{
add_quad(x1, y1, x2, y2, x3, y3, x4, y4, color, color, color, color);
}
/** Add a quad with four arbitrary coordinates and a color for each. */
void add_quad(float x1,
float y1,
float x2,
float y2,
float x3,
float y3,
float x4,
float y4,
const uchar color1[4],
const uchar color2[4],
const uchar color3[4],
const uchar color4[4]);
/** Add four lines of an axis-aligned quad edges. */
void add_wire_quad(float x1, float y1, float x2, float y2, const uchar color[4]);
/** Add a line. */

View File

@ -54,20 +54,14 @@ void SeqScopes::cleanup()
histogram.data.reinitialize(0);
}
/* XXX(@ideasman42): why is this function better than BLI_math version?
* only difference is it does some normalize after, need to double check on this. */
static void rgb_to_yuv_normalized(const float rgb[3], float yuv[3])
static blender::float2 rgb_to_uv_normalized(const float rgb[3])
{
yuv[0] = 0.299f * rgb[0] + 0.587f * rgb[1] + 0.114f * rgb[2];
yuv[1] = 0.492f * (rgb[2] - yuv[0]);
yuv[2] = 0.877f * (rgb[0] - yuv[0]);
float3 yuv;
rgb_to_yuv(rgb[0], rgb[1], rgb[2], &yuv.x, &yuv.y, &yuv.z, BLI_YUV_ITU_BT709);
/* Normalize. */
yuv[1] *= 255.0f / (122 * 2.0f);
yuv[1] += 0.5f;
yuv[2] *= 255.0f / (157 * 2.0f);
yuv[2] += 0.5f;
/* Normalize: UV range is +/- 0.615 */
float2 uv = yuv.yz() * (0.5f / 0.615f) + 0.5f;
return math::clamp(uv, 0.0f, 1.0f);
}
static void scope_put_pixel(const uchar *table, uchar *pos)
@ -420,60 +414,22 @@ void ScopeHistogram::calc_from_ibuf(const ImBuf *ibuf)
}
}
static void vectorscope_put_cross(uchar r, uchar g, uchar b, uchar *tgt, int w, int h, int size)
{
float rgb[3], yuv[3];
uchar *p;
rgb[0] = float(r) / 255.0f;
rgb[1] = float(g) / 255.0f;
rgb[2] = float(b) / 255.0f;
rgb_to_yuv_normalized(rgb, yuv);
p = tgt + 4 * (w * int(yuv[2] * (h - 3) + 1) + int(yuv[1] * (w - 3) + 1));
if (r == 0 && g == 0 && b == 0) {
r = 255;
}
for (int y = -size; y <= size; y++) {
for (int x = -size; x <= size; x++) {
uchar *q = p + 4 * (y * w + x);
q[0] = r;
q[1] = g;
q[2] = b;
q[3] = 255;
}
}
}
static ImBuf *make_vectorscope_view_from_ibuf_byte(ImBuf *ibuf)
{
#ifdef DEBUG_TIME
SCOPED_TIMER_AVERAGED(__func__);
#endif
ImBuf *rval = IMB_allocImBuf(515, 515, 32, IB_rect);
int w = 512;
int h = 512;
ImBuf *rval = IMB_allocImBuf(w, h, 32, IB_rect);
int x, y;
const uchar *src = ibuf->byte_buffer.data;
uchar *tgt = rval->byte_buffer.data;
float rgb[3], yuv[3];
int w = 515;
int h = 515;
float scope_gamma = 0.2;
float rgb[3];
uchar wtable[256];
for (x = 0; x < 256; x++) {
wtable[x] = uchar(pow((float(x) + 1.0f) / 256.0f, scope_gamma) * 255.0f);
}
for (x = 0; x < 256; x++) {
vectorscope_put_cross(255, 0, 255 - x, tgt, w, h, 1);
vectorscope_put_cross(255, x, 0, tgt, w, h, 1);
vectorscope_put_cross(255 - x, 255, 0, tgt, w, h, 1);
vectorscope_put_cross(0, 255, x, tgt, w, h, 1);
vectorscope_put_cross(0, 255 - x, 255, tgt, w, h, 1);
vectorscope_put_cross(x, 0, 255, tgt, w, h, 1);
}
init_wave_table(math::midpoint(ibuf->x, ibuf->y), wtable);
for (y = 0; y < ibuf->y; y++) {
for (x = 0; x < ibuf->x; x++) {
@ -483,15 +439,13 @@ static ImBuf *make_vectorscope_view_from_ibuf_byte(ImBuf *ibuf)
rgb[0] = float(src1[0]) / 255.0f;
rgb[1] = float(src1[1]) / 255.0f;
rgb[2] = float(src1[2]) / 255.0f;
rgb_to_yuv_normalized(rgb, yuv);
float2 uv = rgb_to_uv_normalized(rgb);
p = tgt + 4 * (w * int(yuv[2] * (h - 3) + 1) + int(yuv[1] * (w - 3) + 1));
p = tgt + 4 * (w * int(uv.y * (h - 1)) + int(uv.x * (w - 1)));
scope_put_pixel(wtable, (uchar *)p);
}
}
vectorscope_put_cross(0, 0, 0, tgt, w, h, 3);
return rval;
}
@ -500,13 +454,13 @@ static ImBuf *make_vectorscope_view_from_ibuf_float(ImBuf *ibuf)
#ifdef DEBUG_TIME
SCOPED_TIMER_AVERAGED(__func__);
#endif
ImBuf *rval = IMB_allocImBuf(515, 515, 32, IB_rect);
int w = 512;
int h = 512;
ImBuf *rval = IMB_allocImBuf(w, h, 32, IB_rect);
int x, y;
const float *src = ibuf->float_buffer.data;
uchar *tgt = rval->byte_buffer.data;
float rgb[3], yuv[3];
int w = 515;
int h = 515;
float rgb[3];
float scope_gamma = 0.2;
uchar wtable[256];
@ -514,15 +468,6 @@ static ImBuf *make_vectorscope_view_from_ibuf_float(ImBuf *ibuf)
wtable[x] = uchar(pow((float(x) + 1.0f) / 256.0f, scope_gamma) * 255.0f);
}
for (x = 0; x <= 255; x++) {
vectorscope_put_cross(255, 0, 255 - x, tgt, w, h, 1);
vectorscope_put_cross(255, x, 0, tgt, w, h, 1);
vectorscope_put_cross(255 - x, 255, 0, tgt, w, h, 1);
vectorscope_put_cross(0, 255, x, tgt, w, h, 1);
vectorscope_put_cross(0, 255 - x, 255, tgt, w, h, 1);
vectorscope_put_cross(x, 0, 255, tgt, w, h, 1);
}
for (y = 0; y < ibuf->y; y++) {
for (x = 0; x < ibuf->x; x++) {
const float *src1 = src + 4 * (ibuf->x * y + x);
@ -532,15 +477,13 @@ static ImBuf *make_vectorscope_view_from_ibuf_float(ImBuf *ibuf)
clamp_v3(rgb, 0.0f, 1.0f);
rgb_to_yuv_normalized(rgb, yuv);
float2 uv = rgb_to_uv_normalized(rgb);
p = tgt + 4 * (w * int(yuv[2] * (h - 3) + 1) + int(yuv[1] * (w - 3) + 1));
p = tgt + 4 * (w * int(uv.y * (h - 1)) + int(uv.x * (w - 1)));
scope_put_pixel(wtable, (uchar *)p);
}
}
vectorscope_put_cross(0, 0, 0, tgt, w, h, 3);
return rval;
}