diff --git a/scripts/startup/bl_ui/space_image.py b/scripts/startup/bl_ui/space_image.py index adcbdc7fb8e..ebce4347186 100644 --- a/scripts/startup/bl_ui/space_image.py +++ b/scripts/startup/bl_ui/space_image.py @@ -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): diff --git a/source/blender/blenkernel/intern/colortools.cc b/source/blender/blenkernel/intern/colortools.cc index 02418a2d4d7..b918d68dd77 100644 --- a/source/blender/blenkernel/intern/colortools.cc +++ b/source/blender/blenkernel/intern/colortools.cc @@ -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( @@ -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( MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "vectorscope point channel")); + scopes->vecscope_rgb = static_cast( + 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) diff --git a/source/blender/editors/interface/interface_draw.cc b/source/blender/editors/interface/interface_draw.cc index a76bb8256d1..7e530476914 100644 --- a/source/blender/editors/interface/interface_draw.cc +++ b/source/blender/editors/interface/interface_draw.cc @@ -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(); } diff --git a/source/blender/makesdna/DNA_color_types.h b/source/blender/makesdna/DNA_color_types.h index 7b17b91bbaf..80d062446f3 100644 --- a/source/blender/makesdna/DNA_color_types.h +++ b/source/blender/makesdna/DNA_color_types.h @@ -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]; diff --git a/source/blender/makesrna/intern/rna_color.cc b/source/blender/makesrna/intern/rna_color.cc index 94de4220d12..14b3f3439bc 100644 --- a/source/blender/makesrna/intern/rna_color.cc +++ b/source/blender/makesrna/intern/rna_color.cc @@ -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)