UI: Image Editor Vectorscope Improvement

Update the look of image editor Vectorscope widget (design #116973):
- Colored and Luma options for the point cloud,
- The circles are no longer very low poly,
- Overall grid/background colors are tuned.
- Primary color locations have text labels.

Images in the PR.

Pull Request: https://projects.blender.org/blender/blender/pulls/116974
This commit is contained in:
JonasDichelle
2024-02-06 12:22:48 +01:00
committed by Aras Pranckevicius
parent 291735971c
commit 567455124d
5 changed files with 220 additions and 84 deletions

View File

@@ -1431,8 +1431,11 @@ class IMAGE_PT_view_vectorscope(ImageScopesPanel, Panel):
layout = self.layout
sima = context.space_data
layout.template_vectorscope(sima, "scopes")
layout.prop(sima.scopes, "vectorscope_alpha")
row = layout.split(factor=0.75)
row.prop(sima.scopes, "vectorscope_alpha")
row.prop(sima.scopes, "vectorscope_mode", text="")
class IMAGE_PT_sample_line(ImageScopesPanel, Panel):

View File

@@ -1359,6 +1359,12 @@ static void save_sample_line(
scopes->vecscope[idx + 0] = yuv[1];
scopes->vecscope[idx + 1] = yuv[2];
int color_idx = (idx / 2) * 4;
scopes->vecscope_rgb[color_idx + 0] = rgb[0];
scopes->vecscope_rgb[color_idx + 1] = rgb[1];
scopes->vecscope_rgb[color_idx + 2] = rgb[2];
scopes->vecscope_rgb[color_idx + 3] = scopes->vecscope_alpha;
/* Waveform. */
switch (scopes->wavefrm_mode) {
case SCOPES_WAVEFRM_RGB:
@@ -1707,6 +1713,7 @@ void BKE_scopes_update(Scopes *scopes,
}
if (scopes->vecscope) {
MEM_freeN(scopes->vecscope);
MEM_freeN(scopes->vecscope_rgb);
}
scopes->waveform_1 = static_cast<float *>(
@@ -1717,6 +1724,8 @@ void BKE_scopes_update(Scopes *scopes,
MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "waveform point channel 3"));
scopes->vecscope = static_cast<float *>(
MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "vectorscope point channel"));
scopes->vecscope_rgb = static_cast<float *>(
MEM_callocN(scopes->waveform_tot * 4 * sizeof(float), "vectorscope color channel"));
if (ibuf->float_buffer.data) {
cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
@@ -1794,6 +1803,7 @@ void BKE_scopes_free(Scopes *scopes)
MEM_SAFE_FREE(scopes->waveform_2);
MEM_SAFE_FREE(scopes->waveform_3);
MEM_SAFE_FREE(scopes->vecscope);
MEM_SAFE_FREE(scopes->vecscope_rgb);
}
void BKE_scopes_new(Scopes *scopes)
@@ -1810,6 +1820,7 @@ void BKE_scopes_new(Scopes *scopes)
scopes->waveform_2 = nullptr;
scopes->waveform_3 = nullptr;
scopes->vecscope = nullptr;
scopes->vecscope_rgb = nullptr;
}
void BKE_color_managed_display_settings_init(ColorManagedDisplaySettings *settings)

View File

@@ -610,6 +610,44 @@ static void waveform_draw_one(float *waveform, int waveform_num, const float col
GPU_batch_discard(batch);
}
static void waveform_draw_rgb(float *waveform, int waveform_num, float *col)
{
GPUVertFormat format = {0};
const uint pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
const uint col_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, waveform_num);
GPU_vertbuf_attr_fill(vbo, pos_id, waveform);
GPU_vertbuf_attr_fill(vbo, col_id, col);
GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, nullptr, GPU_BATCH_OWNS_VBO);
GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_SMOOTH_COLOR);
GPU_batch_draw(batch);
GPU_batch_discard(batch);
}
static void circle_draw_rgb(float *points, int tot_points, float *col, GPUPrimType prim)
{
GPUVertFormat format = {0};
const uint pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
const uint col_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, tot_points);
GPU_vertbuf_attr_fill(vbo, pos_id, points);
GPU_vertbuf_attr_fill(vbo, col_id, col);
GPUBatch *batch = GPU_batch_create_ex(prim, vbo, nullptr, GPU_BATCH_OWNS_VBO);
GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_SMOOTH_COLOR);
GPU_batch_draw(batch);
GPU_batch_discard(batch);
}
void ui_draw_but_WAVEFORM(ARegion * /*region*/,
uiBut *but,
const uiWidgetColors * /*wcol*/,
@@ -687,8 +725,6 @@ void ui_draw_but_WAVEFORM(ARegion * /*region*/,
/* Flush text cache before drawing things on top. */
BLF_batch_draw_flush();
GPU_blend(GPU_BLEND_ALPHA);
GPUVertFormat *format = immVertexFormat();
const uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
@@ -863,11 +899,12 @@ static float polar_to_y(float center, float diam, float ampli, float angle)
}
static void vectorscope_draw_target(
uint pos, float centerx, float centery, float diam, const float colf[3])
uint pos, float centerx, float centery, float diam, const float colf[3], char label)
{
float y, u, v;
float tangle = 0.0f, tampli;
float dangle, dampli, dangle2, dampli2;
char labelstr[2] = {label, '\0'};
rgb_to_yuv(colf[0], colf[1], colf[2], &y, &u, &v, BLI_YUV_ITU_BT709);
@@ -905,56 +942,15 @@ static void vectorscope_draw_target(
immVertex2f(pos,
polar_to_x(centerx, diam, tampli + dampli, tangle - dangle),
polar_to_y(centery, diam, tampli + dampli, tangle - dangle));
immEnd();
/* big target vary by 10 degree and 20% amplitude */
immUniformColor4f(1.0f, 1.0f, 1.0f, 0.12f);
dangle = DEG2RADF(10.0f);
dampli = 0.2f * tampli;
dangle2 = DEG2RADF(5.0f);
dampli2 = 0.5f * dampli;
immBegin(GPU_PRIM_LINE_STRIP, 3);
immVertex2f(pos,
polar_to_x(centerx, diam, tampli + dampli - dampli2, tangle + dangle),
polar_to_y(centery, diam, tampli + dampli - dampli2, tangle + dangle));
immVertex2f(pos,
polar_to_x(centerx, diam, tampli + dampli, tangle + dangle),
polar_to_y(centery, diam, tampli + dampli, tangle + dangle));
immVertex2f(pos,
polar_to_x(centerx, diam, tampli + dampli, tangle + dangle - dangle2),
polar_to_y(centery, diam, tampli + dampli, tangle + dangle - dangle2));
immEnd();
immBegin(GPU_PRIM_LINE_STRIP, 3);
immVertex2f(pos,
polar_to_x(centerx, diam, tampli - dampli + dampli2, tangle + dangle),
polar_to_y(centery, diam, tampli - dampli + dampli2, tangle + dangle));
immVertex2f(pos,
polar_to_x(centerx, diam, tampli - dampli, tangle + dangle),
polar_to_y(centery, diam, tampli - dampli, tangle + dangle));
immVertex2f(pos,
polar_to_x(centerx, diam, tampli - dampli, tangle + dangle - dangle2),
polar_to_y(centery, diam, tampli - dampli, tangle + dangle - dangle2));
immEnd();
immBegin(GPU_PRIM_LINE_STRIP, 3);
immVertex2f(pos,
polar_to_x(centerx, diam, tampli - dampli + dampli2, tangle - dangle),
polar_to_y(centery, diam, tampli - dampli + dampli2, tangle - dangle));
immVertex2f(pos,
polar_to_x(centerx, diam, tampli - dampli, tangle - dangle),
polar_to_y(centery, diam, tampli - dampli, tangle - dangle));
immVertex2f(pos,
polar_to_x(centerx, diam, tampli - dampli, tangle - dangle + dangle2),
polar_to_y(centery, diam, tampli - dampli, tangle - dangle + dangle2));
immEnd();
immBegin(GPU_PRIM_LINE_STRIP, 3);
immVertex2f(pos,
polar_to_x(centerx, diam, tampli + dampli - dampli2, tangle - dangle),
polar_to_y(centery, diam, tampli + dampli - dampli2, tangle - dangle));
immVertex2f(pos,
polar_to_x(centerx, diam, tampli + dampli, tangle - dangle),
polar_to_y(centery, diam, tampli + dampli, tangle - dangle));
immVertex2f(pos,
polar_to_x(centerx, diam, tampli + dampli, tangle - dangle + dangle2),
polar_to_y(centery, diam, tampli + dampli, tangle - dangle + dangle2));
/* draw color letter as text */
BLF_color4f(BLF_default(), 1.0f, 1.0f, 1.0f, 0.3f);
BLF_draw_default(polar_to_x(centerx, diam, tampli, tangle) + 5,
polar_to_y(centery, diam, tampli, tangle),
0,
labelstr,
strlen(labelstr));
immEnd();
}
@@ -967,14 +963,16 @@ void ui_draw_but_VECTORSCOPE(ARegion * /*region*/,
Scopes *scopes = (Scopes *)but->poin;
const float colors[6][3] = {
{0.75, 0.0, 0.0},
{0.75, 0.75, 0.0},
{0.0, 0.75, 0.0},
{0.0, 0.75, 0.75},
{0.0, 0.0, 0.75},
{0.75, 0.0, 0.75},
{0.75, 0.0, 0.0}, /* Red */
{0.75, 0.75, 0.0}, /* Yellow */
{0.0, 0.75, 0.0}, /* Green */
{0.0, 0.75, 0.75}, /* Cyan */
{0.0, 0.0, 0.75}, /* Blue */
{0.75, 0.0, 0.75}, /* Magenta */
};
const char color_names[] = {'R', 'Y', 'G', 'C', 'B', 'M'};
rctf rect{};
rect.xmin = float(recti->xmin + 1);
rect.xmax = float(recti->xmax - 1);
@@ -987,8 +985,9 @@ void ui_draw_but_VECTORSCOPE(ARegion * /*region*/,
const float centery = rect.ymin + h * 0.5f;
const float diam = (w < h) ? w : h;
const float alpha = scopes->vecscope_alpha * scopes->vecscope_alpha * scopes->vecscope_alpha;
const float alpha = scopes->vecscope_alpha;
GPU_line_smooth(true);
GPU_blend(GPU_BLEND_ALPHA);
float color[4];
@@ -1013,10 +1012,118 @@ void ui_draw_but_VECTORSCOPE(ARegion * /*region*/,
const uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
const int increment = 6;
const int tot_points = int(360 / increment);
const float r = 0.5f;
float step = 360.0f / (tot_points - 1);
float circle_fill_points[(tot_points * 2) + 2];
float circle_fill_vertex_colors[(tot_points * 4) + 4];
/* draw filled RGB circle for background, only for LUMA mode */
if (scopes->vecscope_mode == SCOPES_VECSCOPE_LUMA) {
/* Initialize center point and color */
circle_fill_points[0] = centerx;
circle_fill_points[1] = centery;
circle_fill_vertex_colors[0] = 0.2f;
circle_fill_vertex_colors[1] = 0.2f;
circle_fill_vertex_colors[2] = 0.2f;
circle_fill_vertex_colors[3] = 0.8f;
for (int i = 0; i < tot_points; i++) {
float angle = step * i;
const float a = DEG2RADF(angle);
const float x = polar_to_x(centerx, diam, r, a);
const float y = polar_to_y(centery, diam, r, a);
const float u = polar_to_x(0.0f, 1.0, 1.0f, a);
const float v = polar_to_y(0.0f, 1.0, 1.0f, a);
circle_fill_points[(i + 1) * 2] = x;
circle_fill_points[(i + 1) * 2 + 1] = y;
float r, g, b;
yuv_to_rgb(0.5f, u, v, &r, &g, &b, BLI_YUV_ITU_BT709);
circle_fill_vertex_colors[(i + 1) * 4] = r * 0.2f;
circle_fill_vertex_colors[(i + 1) * 4 + 1] = g * 0.2f;
circle_fill_vertex_colors[(i + 1) * 4 + 2] = b * 0.2f;
circle_fill_vertex_colors[(i + 1) * 4 + 3] = 0.8f;
}
GPU_blend(GPU_BLEND_ALPHA);
circle_draw_rgb(
circle_fill_points, tot_points + 2, circle_fill_vertex_colors, GPU_PRIM_TRI_FAN);
}
/* draw filled Gray circle for background, only for RGB mode */
else if (scopes->vecscope_mode == SCOPES_VECSCOPE_RGB) {
GPU_blend(GPU_BLEND_NONE);
immBegin(GPU_PRIM_TRI_FAN, tot_points + 2);
immUniformColor3f(0.16f, 0.16f, 0.16f);
immVertex2f(pos, centerx, centery);
for (int i = 0; i <= 360; i += increment) {
const float a = DEG2RADF(float(i));
immVertex2f(pos, polar_to_x(centerx, diam, r, a), polar_to_y(centery, diam, r, a));
}
immEnd();
}
/* draw RGB ring */
float circle_points[(tot_points * 2) + 3] = {};
float circle_vertex_colors[(tot_points * 4) + 5] = {};
for (int i = 0; i < tot_points; i++) {
float angle = step * i;
const float a = DEG2RADF(angle);
const float x = polar_to_x(centerx, diam, 0.5f, a);
const float y = polar_to_y(centery, diam, 0.5f, a);
circle_points[i * 2] = x;
circle_points[i * 2 + 1] = y;
const float u = polar_to_x(0.0f, 1.0, 1.0f, a);
const float v = polar_to_y(0.0f, 1.0, 1.0f, a);
float r, g, b;
yuv_to_rgb(0.5f, u, v, &r, &g, &b, BLI_YUV_ITU_BT709);
circle_vertex_colors[i * 4] = r;
circle_vertex_colors[i * 4 + 1] = g;
circle_vertex_colors[i * 4 + 2] = b;
circle_vertex_colors[i * 4 + 3] = 0.8f;
}
GPU_blend(GPU_BLEND_ALPHA);
GPU_line_width(2.5f);
circle_draw_rgb(circle_points, tot_points, circle_vertex_colors, GPU_PRIM_LINE_LOOP);
GPU_line_width(1.5f);
/* inner circles */
GPU_blend(GPU_BLEND_ADDITIVE);
for (int j = 0; j < 4; j++) {
float inner_circle_points[(tot_points * 2) + 3] = {};
float inner_circle_colors[(tot_points * 4) + 5] = {};
const float r = (j + 1) * 0.1f;
for (int i = 0; i < tot_points; i++) {
float angle = step * i;
const float a = DEG2RADF(angle);
inner_circle_points[i * 2] = polar_to_x(centerx, diam, r, a);
inner_circle_points[i * 2 + 1] = polar_to_y(centery, diam, r, a);
inner_circle_colors[i * 4] = 0.1f;
inner_circle_colors[i * 4 + 1] = 0.1f;
inner_circle_colors[i * 4 + 2] = 0.1f;
inner_circle_colors[i * 4 + 3] = 0.8f;
}
circle_draw_rgb(inner_circle_points, tot_points, inner_circle_colors, GPU_PRIM_LINE_LOOP);
}
immUniformColor4f(1.0f, 1.0f, 1.0f, 0.08f);
/* draw grid elements */
/* cross */
immUniformColor4f(1.0f, 1.0f, 1.0f, 0.1f);
immBegin(GPU_PRIM_LINES, 4);
immVertex2f(pos, centerx - (diam * 0.5f) - 5, centery);
@@ -1027,19 +1134,9 @@ void ui_draw_but_VECTORSCOPE(ARegion * /*region*/,
immEnd();
/* circles */
for (int j = 0; j < 5; j++) {
const int increment = 15;
immBegin(GPU_PRIM_LINE_LOOP, int(360 / increment));
for (int i = 0; i <= 360 - increment; i += increment) {
const float a = DEG2RADF(float(i));
const float r = (j + 1) * 0.1f;
immVertex2f(pos, polar_to_x(centerx, diam, r, a), polar_to_y(centery, diam, r, a));
}
immEnd();
}
/* skin tone line */
immUniformColor4f(1.0f, 0.4f, 0.0f, 0.2f);
GPU_blend(GPU_BLEND_ADDITIVE);
immUniformColor3f(0.25f, 0.25f, 0.25f);
immBegin(GPU_PRIM_LINES, 2);
immVertex2f(
@@ -1050,21 +1147,26 @@ void ui_draw_but_VECTORSCOPE(ARegion * /*region*/,
/* saturation points */
for (int i = 0; i < 6; i++) {
vectorscope_draw_target(pos, centerx, centery, diam, colors[i]);
vectorscope_draw_target(pos, centerx, centery, diam, colors[i], color_names[i]);
}
if (scopes->ok && scopes->vecscope != nullptr) {
/* pixel point cloud */
const float col[3] = {alpha, alpha, alpha};
GPU_blend(GPU_BLEND_ADDITIVE);
GPU_point_size(1.0);
GPU_matrix_push();
GPU_matrix_translate_2f(centerx, centery);
GPU_matrix_scale_1f(diam);
waveform_draw_one(scopes->vecscope, scopes->waveform_tot, col);
const float col[3] = {alpha, alpha, alpha};
if (scopes->vecscope_mode == SCOPES_VECSCOPE_RGB) {
GPU_blend(GPU_BLEND_ALPHA);
waveform_draw_rgb(scopes->vecscope, scopes->waveform_tot, scopes->vecscope_rgb);
}
else if (scopes->vecscope_mode == SCOPES_VECSCOPE_LUMA) {
GPU_blend(GPU_BLEND_ADDITIVE);
waveform_draw_one(scopes->vecscope, scopes->waveform_tot, col);
}
GPU_matrix_pop();
}

View File

@@ -150,21 +150,22 @@ typedef struct Scopes {
int ok;
int sample_full;
int sample_lines;
float accuracy;
int wavefrm_mode;
int vecscope_mode;
int wavefrm_height;
int vecscope_height;
int waveform_tot;
float accuracy;
float wavefrm_alpha;
float wavefrm_yfac;
int wavefrm_height;
float vecscope_alpha;
int vecscope_height;
float minmax[3][2];
struct Histogram hist;
float *waveform_1;
float *waveform_2;
float *waveform_3;
float *vecscope;
int waveform_tot;
char _pad[4];
float *vecscope_rgb;
} Scopes;
/** #Scopes.wavefrm_mode */
@@ -177,6 +178,12 @@ enum {
SCOPES_WAVEFRM_RGB = 5,
};
/** #Scopes.vecscope_mode */
enum {
SCOPES_VECSCOPE_RGB = 0,
SCOPES_VECSCOPE_LUMA = 1,
};
typedef struct ColorManagedViewSettings {
int flag;
char _pad[4];

View File

@@ -1144,6 +1144,12 @@ static void rna_def_scopes(BlenderRNA *brna)
{0, nullptr, 0, nullptr, nullptr},
};
static const EnumPropertyItem prop_vecscope_mode_items[] = {
{SCOPES_VECSCOPE_LUMA, "LUMA", ICON_COLOR, "Luma", ""},
{SCOPES_VECSCOPE_RGB, "RGB", ICON_COLOR, "Red Green Blue", ""},
{0, nullptr, 0, nullptr, nullptr},
};
srna = RNA_def_struct(brna, "Scopes", nullptr);
RNA_def_struct_ui_text(srna, "Scopes", "Scopes for statistical view of an image");
@@ -1176,10 +1182,17 @@ static void rna_def_scopes(BlenderRNA *brna)
RNA_def_property_range(prop, 0, 1);
RNA_def_property_ui_text(prop, "Waveform Opacity", "Opacity of the points");
prop = RNA_def_property(srna, "vectorscope_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, "Scopes", "vecscope_mode");
RNA_def_property_enum_items(prop, prop_vecscope_mode_items);
RNA_def_property_ui_text(prop, "Vectorscope Mode", "");
RNA_def_property_update(prop, 0, "rna_Scopes_update");
prop = RNA_def_property(srna, "vectorscope_alpha", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, "Scopes", "vecscope_alpha");
RNA_def_property_range(prop, 0, 1);
RNA_def_property_ui_text(prop, "Vectorscope Opacity", "Opacity of the points");
RNA_def_property_update(prop, 0, "rna_Scopes_update");
}
static void rna_def_colormanage(BlenderRNA *brna)