From 235fdc63567bf2a66b7f35e84d118624f71e6495 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 14 Aug 2025 22:25:52 +0200 Subject: [PATCH] Color Management: Fix wrong use of display color space * PROP_COLOR_GAMMA is sRGB, not display space * Hex colors are always sRGB * Image byte buffers are in byte_buffer.colorspace Fixes for sequencer text, image painting, render stamp and tooltips. The default display space is sRGB, so this change will not be noticed in most files. Ref #144911 Pull Request: https://projects.blender.org/blender/blender/pulls/144565 --- source/blender/blenfont/BLF_api.hh | 14 +- source/blender/blenfont/intern/blf.cc | 24 +-- .../blenfont/intern/blf_internal_types.hh | 8 +- source/blender/blenkernel/BKE_image.hh | 10 +- source/blender/blenkernel/intern/image.cc | 143 ++++-------------- source/blender/blenkernel/intern/image_gen.cc | 6 +- .../eyedropper_grease_pencil_color.cc | 8 +- .../regions/interface_region_tooltip.cc | 83 ++++++---- .../blender/editors/render/render_opengl.cc | 10 +- .../editors/sculpt_paint/paint_image.cc | 9 +- .../editors/sculpt_paint/paint_image_2d.cc | 113 ++++++++------ .../editors/sculpt_paint/paint_image_proj.cc | 9 +- .../editors/sculpt_paint/paint_intern.hh | 5 +- .../blender/editors/space_image/image_draw.cc | 2 +- .../editors/space_node/node_socket_tooltip.cc | 1 - source/blender/imbuf/IMB_imbuf.hh | 57 ++----- source/blender/imbuf/intern/rectop.cc | 117 +++----------- source/blender/makesrna/intern/rna_rna.cc | 6 +- source/blender/python/generic/blf_py_api.cc | 31 +--- source/blender/render/intern/pipeline.cc | 5 +- .../intern/effects/vse_effect_text.cc | 17 ++- 21 files changed, 249 insertions(+), 429 deletions(-) diff --git a/source/blender/blenfont/BLF_api.hh b/source/blender/blenfont/BLF_api.hh index 6ba18f50d70..9b03eb3a3e2 100644 --- a/source/blender/blenfont/BLF_api.hh +++ b/source/blender/blenfont/BLF_api.hh @@ -32,9 +32,9 @@ struct ResultBLF; struct rcti; namespace blender::ocio { -class Display; +class ColorSpace; } // namespace blender::ocio -using ColorManagedDisplay = blender::ocio::Display; +using ColorSpace = blender::ocio::ColorSpace; int BLF_init(); void BLF_exit(); @@ -350,12 +350,8 @@ void BLF_shadow_offset(int fontid, int x, int y); * The image is assumed to have 4 color channels (RGBA) per pixel. * When done, call this function with null buffer pointers. */ -void BLF_buffer(int fontid, - float *fbuf, - unsigned char *cbuf, - int w, - int h, - const ColorManagedDisplay *display); +void BLF_buffer( + int fontid, float *fbuf, unsigned char *cbuf, int w, int h, const ColorSpace *colorspace); /** * Opaque structure used to push/pop values set by the #BLF_buffer function. @@ -379,7 +375,7 @@ void BLF_buffer_state_free(BLFBufferState *buffer_state); /** * Set the color to be used for text. */ -void BLF_buffer_col(int fontid, const float rgba[4]) ATTR_NONNULL(2); +void BLF_buffer_col(int fontid, const float srgb_color[4]) ATTR_NONNULL(2); /** * Draw the string into the buffer, this function draw in both buffer, diff --git a/source/blender/blenfont/intern/blf.cc b/source/blender/blenfont/intern/blf.cc index db265845706..e93d1f0cbec 100644 --- a/source/blender/blenfont/intern/blf.cc +++ b/source/blender/blenfont/intern/blf.cc @@ -944,8 +944,7 @@ void BLF_shadow_offset(int fontid, int x, int y) } } -void BLF_buffer( - int fontid, float *fbuf, uchar *cbuf, int w, int h, const ColorManagedDisplay *display) +void BLF_buffer(int fontid, float *fbuf, uchar *cbuf, int w, int h, const ColorSpace *colorspace) { FontBLF *font = blf_get(fontid); @@ -954,7 +953,7 @@ void BLF_buffer( font->buf_info.cbuf = cbuf; font->buf_info.dims[0] = w; font->buf_info.dims[1] = h; - font->buf_info.display = display; + font->buf_info.colorspace = colorspace; } } @@ -1004,12 +1003,12 @@ void BLF_buffer_state_free(BLFBufferState *buffer_state) MEM_delete(buffer_state); } -void BLF_buffer_col(int fontid, const float rgba[4]) +void BLF_buffer_col(int fontid, const float srgb_color[4]) { FontBLF *font = blf_get(fontid); if (font) { - copy_v4_v4(font->buf_info.col_init, rgba); + copy_v4_v4(font->buf_info.col_init, srgb_color); } } @@ -1017,14 +1016,19 @@ void blf_draw_buffer__start(FontBLF *font) { FontBufInfoBLF *buf_info = &font->buf_info; - rgba_float_to_uchar(buf_info->col_char, buf_info->col_init); + /* This will be written to scene linear image buffer, so convert to that. */ + IMB_colormanagement_srgb_to_scene_linear_v3(buf_info->col_float, buf_info->col_init); + buf_info->col_float[3] = buf_info->col_init[3]; - if (buf_info->display) { - copy_v4_v4(buf_info->col_float, buf_info->col_init); - IMB_colormanagement_display_to_scene_linear_v3(buf_info->col_float, buf_info->display); + /* Convert to the colorspace of the byte image buffer, assumed sRGB if not specified. */ + if (buf_info->colorspace) { + float col_char[4]; + copy_v4_v4(col_char, buf_info->col_float); + IMB_colormanagement_scene_linear_to_colorspace_v3(col_char, buf_info->colorspace); + rgba_float_to_uchar(buf_info->col_char, col_char); } else { - srgb_to_linearrgb_v4(buf_info->col_float, buf_info->col_init); + rgba_float_to_uchar(buf_info->col_char, buf_info->col_init); } } void blf_draw_buffer__end() {} diff --git a/source/blender/blenfont/intern/blf_internal_types.hh b/source/blender/blenfont/intern/blf_internal_types.hh index 9dde72033fc..af0ea2cc2a7 100644 --- a/source/blender/blenfont/intern/blf_internal_types.hh +++ b/source/blender/blenfont/intern/blf_internal_types.hh @@ -35,9 +35,9 @@ class VertBuf; struct GPUVertBufRaw; namespace blender::ocio { -class Display; +class ColorSpace; } // namespace blender::ocio -using ColorManagedDisplay = blender::ocio::Display; +using ColorSpace = blender::ocio::ColorSpace; #include FT_MULTIPLE_MASTERS_H /* Variable font support. */ @@ -230,8 +230,8 @@ struct FontBufInfoBLF { /** Buffer size, keep signed so comparisons with negative values work. */ int dims[2]; - /** Display device used for color management. */ - const ColorManagedDisplay *display; + /** Colorspace of the byte buffer (float is scene linear). */ + const ColorSpace *colorspace; /** The color, the alphas is get from the glyph! (color is sRGB space). */ float col_init[4]; diff --git a/source/blender/blenkernel/BKE_image.hh b/source/blender/blenkernel/BKE_image.hh index 7fdd00fc231..c49e0dd809c 100644 --- a/source/blender/blenkernel/BKE_image.hh +++ b/source/blender/blenkernel/BKE_image.hh @@ -17,6 +17,11 @@ namespace blender::gpu { class Texture; } // namespace blender::gpu +namespace blender::ocio { +class ColorSpace; +} // namespace blender::ocio +using ColorSpace = blender::ocio::ColorSpace; + struct rcti; struct Depsgraph; struct ID; @@ -113,10 +118,7 @@ void BKE_stamp_data_free(StampData *stamp_data); void BKE_image_stamp_buf(Scene *scene, Object *camera, const StampData *stamp_data_template, - unsigned char *rect, - float *rectf, - int width, - int height); + ImBuf *ibuf); bool BKE_imbuf_alpha_test(ImBuf *ibuf); bool BKE_imbuf_write_stamp(const Scene *scene, const RenderResult *rr, diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc index 167e4e7912b..fce73231d5e 100644 --- a/source/blender/blenkernel/intern/image.cc +++ b/source/blender/blenkernel/intern/image.cc @@ -2001,18 +2001,13 @@ static void stampdata_from_template(StampData *stamp_data, void BKE_image_stamp_buf(Scene *scene, Object *camera, const StampData *stamp_data_template, - uchar *rect, - float *rectf, - int width, - int height) + ImBuf *ibuf) { StampData stamp_data; int w, h, pad; int x, y, y_ofs; int h_fixed; const int mono = blf_mono_font_render; /* XXX */ - const ColorManagedDisplay *display; - const char *display_device; /* vars for calculating wordwrap */ struct { @@ -2035,13 +2030,10 @@ void BKE_image_stamp_buf(Scene *scene, #define BUFF_MARGIN_X 2 #define BUFF_MARGIN_Y 1 - if (!rect && !rectf) { + if (!ibuf->byte_buffer.data && !ibuf->float_buffer.data) { return; } - display_device = scene->display_settings.display_device; - display = IMB_colormanagement_display_get_named(display_device); - bool do_prefix = (scene->r.stamp & R_STAMP_HIDE_LABELS) == 0; if (stamp_data_template == nullptr) { stampdata(scene, camera, &stamp_data, do_prefix, true); @@ -2057,9 +2049,14 @@ void BKE_image_stamp_buf(Scene *scene, /* set before return */ BLF_size(mono, scene->r.stamp_font_id); - BLF_wordwrap(mono, width - (BUFF_MARGIN_X * 2)); + BLF_wordwrap(mono, ibuf->x - (BUFF_MARGIN_X * 2)); - BLF_buffer(mono, rectf, rect, width, height, display); + BLF_buffer(mono, + ibuf->float_buffer.data, + ibuf->byte_buffer.data, + ibuf->x, + ibuf->y, + ibuf->byte_buffer.colorspace); BLF_buffer_col(mono, scene->r.fg_stamp); pad = BLF_width_max(mono); @@ -2068,19 +2065,15 @@ void BKE_image_stamp_buf(Scene *scene, y_ofs = -BLF_descender(mono); x = 0; - y = height; + y = ibuf->y; if (TEXT_SIZE_CHECK(stamp_data.file, w, h)) { /* Top left corner */ y -= h; /* also a little of space to the background. */ - buf_rectfill_area(rect, - rectf, - width, - height, + IMB_rectfill_area(ibuf, scene->r.bg_stamp, - display, x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, @@ -2099,16 +2092,8 @@ void BKE_image_stamp_buf(Scene *scene, y -= h; /* and space for background. */ - buf_rectfill_area(rect, - rectf, - width, - height, - scene->r.bg_stamp, - display, - 0, - y - BUFF_MARGIN_Y, - w + BUFF_MARGIN_X, - y + h + BUFF_MARGIN_Y); + IMB_rectfill_area( + ibuf, scene->r.bg_stamp, 0, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); BLF_position(mono, x, y + y_ofs, 0.0); BLF_draw_buffer(mono, stamp_data.date, sizeof(stamp_data.date)); @@ -2122,16 +2107,8 @@ void BKE_image_stamp_buf(Scene *scene, y -= h; /* and space for background. */ - buf_rectfill_area(rect, - rectf, - width, - height, - scene->r.bg_stamp, - display, - 0, - y - BUFF_MARGIN_Y, - w + BUFF_MARGIN_X, - y + h + BUFF_MARGIN_Y); + IMB_rectfill_area( + ibuf, scene->r.bg_stamp, 0, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); BLF_position(mono, x, y + y_ofs, 0.0); BLF_draw_buffer(mono, stamp_data.rendertime, sizeof(stamp_data.rendertime)); @@ -2145,16 +2122,8 @@ void BKE_image_stamp_buf(Scene *scene, y -= h; /* and space for background. */ - buf_rectfill_area(rect, - rectf, - width, - height, - scene->r.bg_stamp, - display, - 0, - y - BUFF_MARGIN_Y, - w + BUFF_MARGIN_X, - y + h + BUFF_MARGIN_Y); + IMB_rectfill_area( + ibuf, scene->r.bg_stamp, 0, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); BLF_position(mono, x, y + y_ofs, 0.0); BLF_draw_buffer(mono, stamp_data.memory, sizeof(stamp_data.memory)); @@ -2168,16 +2137,8 @@ void BKE_image_stamp_buf(Scene *scene, y -= h; /* and space for background. */ - buf_rectfill_area(rect, - rectf, - width, - height, - scene->r.bg_stamp, - display, - 0, - y - BUFF_MARGIN_Y, - w + BUFF_MARGIN_X, - y + h + BUFF_MARGIN_Y); + IMB_rectfill_area( + ibuf, scene->r.bg_stamp, 0, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); BLF_position(mono, x, y + y_ofs, 0.0); BLF_draw_buffer(mono, stamp_data.hostname, sizeof(stamp_data.hostname)); @@ -2192,16 +2153,8 @@ void BKE_image_stamp_buf(Scene *scene, y -= h; /* and space for background. */ - buf_rectfill_area(rect, - rectf, - width, - height, - scene->r.bg_stamp, - display, - 0, - y - BUFF_MARGIN_Y, - w + BUFF_MARGIN_X, - y + h + BUFF_MARGIN_Y); + IMB_rectfill_area( + ibuf, scene->r.bg_stamp, 0, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); BLF_position(mono, x, y + y_ofs + (h - h_fixed), 0.0); BLF_draw_buffer(mono, stamp_data.note, sizeof(stamp_data.note)); @@ -2215,12 +2168,8 @@ void BKE_image_stamp_buf(Scene *scene, if (TEXT_SIZE_CHECK(stamp_data.marker, w, h)) { /* extra space for background. */ - buf_rectfill_area(rect, - rectf, - width, - height, + IMB_rectfill_area(ibuf, scene->r.bg_stamp, - display, x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, @@ -2238,12 +2187,8 @@ void BKE_image_stamp_buf(Scene *scene, if (TEXT_SIZE_CHECK(stamp_data.time, w, h)) { /* extra space for background */ - buf_rectfill_area(rect, - rectf, - width, - height, + IMB_rectfill_area(ibuf, scene->r.bg_stamp, - display, x - BUFF_MARGIN_X, y, x + w + BUFF_MARGIN_X, @@ -2260,12 +2205,8 @@ void BKE_image_stamp_buf(Scene *scene, if (TEXT_SIZE_CHECK(stamp_data.frame, w, h)) { /* extra space for background. */ - buf_rectfill_area(rect, - rectf, - width, - height, + IMB_rectfill_area(ibuf, scene->r.bg_stamp, - display, x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, @@ -2282,12 +2223,8 @@ void BKE_image_stamp_buf(Scene *scene, if (TEXT_SIZE_CHECK(stamp_data.frame_range, w, h)) { /* extra space for background. */ - buf_rectfill_area(rect, - rectf, - width, - height, + IMB_rectfill_area(ibuf, scene->r.bg_stamp, - display, x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, @@ -2304,12 +2241,8 @@ void BKE_image_stamp_buf(Scene *scene, if (TEXT_SIZE_CHECK(stamp_data.camera, w, h)) { /* extra space for background. */ - buf_rectfill_area(rect, - rectf, - width, - height, + IMB_rectfill_area(ibuf, scene->r.bg_stamp, - display, x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, @@ -2324,12 +2257,8 @@ void BKE_image_stamp_buf(Scene *scene, if (TEXT_SIZE_CHECK(stamp_data.cameralens, w, h)) { /* extra space for background. */ - buf_rectfill_area(rect, - rectf, - width, - height, + IMB_rectfill_area(ibuf, scene->r.bg_stamp, - display, x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, @@ -2341,15 +2270,11 @@ void BKE_image_stamp_buf(Scene *scene, if (TEXT_SIZE_CHECK(stamp_data.scene, w, h)) { /* Bottom right corner, with an extra space because the BLF API is too strict! */ - x = width - w - 2; + x = ibuf->x - w - 2; /* extra space for background. */ - buf_rectfill_area(rect, - rectf, - width, - height, + IMB_rectfill_area(ibuf, scene->r.bg_stamp, - display, x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, @@ -2363,16 +2288,12 @@ void BKE_image_stamp_buf(Scene *scene, if (TEXT_SIZE_CHECK(stamp_data.strip, w, h)) { /* Top right corner, with an extra space because the BLF API is too strict! */ - x = width - w - pad; - y = height - h; + x = ibuf->x - w - pad; + y = ibuf->y - h; /* extra space for background. */ - buf_rectfill_area(rect, - rectf, - width, - height, + IMB_rectfill_area(ibuf, scene->r.bg_stamp, - display, x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, diff --git a/source/blender/blenkernel/intern/image_gen.cc b/source/blender/blenkernel/intern/image_gen.cc index 16c931dcdf5..fc45dbb555c 100644 --- a/source/blender/blenkernel/intern/image_gen.cc +++ b/source/blender/blenkernel/intern/image_gen.cc @@ -302,10 +302,8 @@ static void checker_board_text( BLF_size(mono, 54.0f); /* hard coded size! */ - /* OCIO_TODO: using nullptr as display will assume using sRGB display - * this is correct since currently generated images are assumed to be in sRGB space, - * but this would probably needed to be fixed in some way - */ + /* Using nullptr will assume the byte buffer has sRGB colorspace, which currently + * matches the default colorspace of new images. */ BLF_buffer(mono, rect_float, rect, width, height, nullptr); const float text_color[4] = {0.0, 0.0, 0.0, 1.0}; diff --git a/source/blender/editors/interface/eyedroppers/eyedropper_grease_pencil_color.cc b/source/blender/editors/interface/eyedroppers/eyedropper_grease_pencil_color.cc index 0ae56d65807..0550e6ba50b 100644 --- a/source/blender/editors/interface/eyedroppers/eyedropper_grease_pencil_color.cc +++ b/source/blender/editors/interface/eyedroppers/eyedropper_grease_pencil_color.cc @@ -313,11 +313,11 @@ static void eyedropper_grease_pencil_color_set(bContext *C, float3 col_conv = eye->color; - /* Convert from linear rgb space to display space because palette and brush colors are in display - * space, and this conversion is needed to undo the conversion to linear performed by - * eyedropper_color_sample_fl. */ + /* Convert from linear rgb space to sRGB space because palette and brush colors are in + * sRGB space, and this conversion is needed to undo the conversion to linear performed by + * eyedropper_color_sample_fl. */ if (eye->display && ELEM(eye->mode, EyeMode::Palette, EyeMode::Brush)) { - IMB_colormanagement_scene_linear_to_display_v3(col_conv, eye->display); + IMB_colormanagement_scene_linear_to_srgb_v3(col_conv, col_conv); } switch (eye->mode) { diff --git a/source/blender/editors/interface/regions/interface_region_tooltip.cc b/source/blender/editors/interface/regions/interface_region_tooltip.cc index 648ead534ba..8f43e886c75 100644 --- a/source/blender/editors/interface/regions/interface_region_tooltip.cc +++ b/source/blender/editors/interface/regions/interface_region_tooltip.cc @@ -805,34 +805,35 @@ static std::unique_ptr ui_tooltip_data_from_tool(bContext *C, static std::string ui_tooltip_color_string(const blender::float4 &color, const blender::StringRefNull title, + const int max_title_len, const bool show_alpha, const bool show_hex = false) { + const int align = max_title_len - title.size(); + if (show_hex) { uchar hex[4]; rgba_float_to_uchar(hex, color); if (show_alpha) { - return fmt::format("{}: #{:02X}{:02X}{:02X}{:02X}", - TIP_(title), + return fmt::format("{}:{: <{}} #{:02X}{:02X}{:02X}{:02X}", + title, + "", + align, int(hex[0]), int(hex[1]), int(hex[2]), int(hex[3])); } return fmt::format( - "{}: #{:02X}{:02X}{:02X}", TIP_(title), int(hex[0]), int(hex[1]), int(hex[2])); + "{}:{: <{}} #{:02X}{:02X}{:02X}", title, "", align, int(hex[0]), int(hex[1]), int(hex[2])); } if (show_alpha) { - return fmt::format("{}: {:.3f} {:.3f} {:.3f} {:.3f}", - TIP_(title), - color[0], - color[1], - color[2], - color[3]); + return fmt::format("{}:{: <{}} {:.3f}", title, "", align, color[3]); } - return fmt::format("{}: {:.3f} {:.3f} {:.3f}", TIP_(title), color[0], color[1], color[2]); + return fmt::format( + "{}:{: <{}} {:.3f} {:.3f} {:.3f}", title, "", align, color[0], color[1], color[2]); }; void UI_tooltip_color_field_add(uiTooltipData &data, @@ -842,25 +843,42 @@ void UI_tooltip_color_field_add(uiTooltipData &data, const ColorManagedDisplay *display, const uiTooltipColorID color_id) { - blender::float4 color = original_color; - if (!is_gamma && display) { - IMB_colormanagement_scene_linear_to_display_v3(color, display); + blender::float4 scene_linear_color = original_color; + blender::float4 display_color = original_color; + blender::float4 srgb_color = original_color; + + if (is_gamma) { + IMB_colormanagement_srgb_to_scene_linear_v3(scene_linear_color, scene_linear_color); + } + else { + IMB_colormanagement_scene_linear_to_display_v3(display_color, display); + IMB_colormanagement_scene_linear_to_srgb_v3(srgb_color, srgb_color); } - const std::string hex_st = ui_tooltip_color_string(color, "Hex", has_alpha, true); + float hsv[4]; + rgb_to_hsv_v(srgb_color, hsv); + hsv[3] = srgb_color[3]; + const blender::StringRefNull hex_title = TIP_("Hex"); + const blender::StringRefNull rgb_title = (is_gamma) ? TIP_("sRGB") : TIP_("Display RGB"); + const blender::StringRefNull hsv_title = TIP_("HSV"); + const blender::StringRefNull alpha_title = TIP_("Alpha"); + const int max_title_len = std::max( + {hex_title.size(), rgb_title.size(), hsv_title.size(), alpha_title.size()}); + + const std::string hex_st = ui_tooltip_color_string( + srgb_color, hex_title, max_title_len, has_alpha, true); const std::string rgba_st = ui_tooltip_color_string( - color, has_alpha ? "RGBA" : "RGB", has_alpha); - - float hsva[4]; - rgb_to_hsv_v(color, hsva); - hsva[3] = color[3]; - const std::string hsva_st = ui_tooltip_color_string(hsva, has_alpha ? "HSVA" : "HSV", has_alpha); + display_color, rgb_title, max_title_len, false); + const std::string hsv_st = ui_tooltip_color_string(hsv, hsv_title, max_title_len, false); + const std::string alpha_st = ui_tooltip_color_string( + scene_linear_color, alpha_title, max_title_len, true); const uiFontStyle *fs = &UI_style_get()->tooltip; BLF_size(blf_mono_font, fs->points * UI_SCALE_FAC); - float w = BLF_width(blf_mono_font, hsva_st.c_str(), hsva_st.size()); + float w = BLF_width(blf_mono_font, hsv_st.c_str(), hsv_st.size()); + /* TODO: This clips wide gamut. Should make a float buffer and draw for display. */ uiTooltipImage image_data; image_data.width = int(w); image_data.height = int(w / (has_alpha ? 4.0f : 3.0f)); @@ -868,35 +886,38 @@ void UI_tooltip_color_field_add(uiTooltipData &data, image_data.border = true; image_data.premultiplied = false; - if (color[3] == 1.0f) { + if (scene_linear_color[3] == 1.0f) { /* No transparency so draw the entire area solid without checkerboard. */ image_data.background = uiTooltipImageBackground::None; - IMB_rectfill_area(image_data.ibuf, color, 1, 1, image_data.width, image_data.height, display); + IMB_rectfill_area( + image_data.ibuf, scene_linear_color, 1, 1, image_data.width, image_data.height); } else { image_data.background = uiTooltipImageBackground::Checkerboard_Fixed; /* Draw one half with transparency. */ IMB_rectfill_area(image_data.ibuf, - color, + scene_linear_color, image_data.width / 2, 1, image_data.width, - image_data.height, - display); + image_data.height); /* Draw the other half with a solid color. */ - color[3] = 1.0f; + scene_linear_color[3] = 1.0f; IMB_rectfill_area( - image_data.ibuf, color, 1, 1, image_data.width / 2, image_data.height, display); + image_data.ibuf, scene_linear_color, 1, 1, image_data.width / 2, image_data.height); } UI_tooltip_text_field_add(data, {}, {}, UI_TIP_STYLE_SPACER, color_id, false); UI_tooltip_text_field_add(data, {}, {}, UI_TIP_STYLE_SPACER, color_id, false); UI_tooltip_image_field_add(data, image_data); UI_tooltip_text_field_add(data, {}, {}, UI_TIP_STYLE_SPACER, color_id, false); - UI_tooltip_text_field_add(data, hex_st, {}, UI_TIP_STYLE_MONO, color_id, false); - UI_tooltip_text_field_add(data, {}, {}, UI_TIP_STYLE_SPACER, color_id, false); UI_tooltip_text_field_add(data, rgba_st, {}, UI_TIP_STYLE_MONO, color_id, false); - UI_tooltip_text_field_add(data, hsva_st, {}, UI_TIP_STYLE_MONO, color_id, false); + UI_tooltip_text_field_add(data, hsv_st, {}, UI_TIP_STYLE_MONO, color_id, false); + if (has_alpha) { + UI_tooltip_text_field_add(data, alpha_st, {}, UI_TIP_STYLE_MONO, color_id, false); + } + UI_tooltip_text_field_add(data, {}, {}, UI_TIP_STYLE_SPACER, color_id, false); + UI_tooltip_text_field_add(data, hex_st, {}, UI_TIP_STYLE_MONO, color_id, false); /* Tooltip now owns a copy of the ImBuf, so we can delete ours. */ IMB_freeImBuf(image_data.ibuf); diff --git a/source/blender/editors/render/render_opengl.cc b/source/blender/editors/render/render_opengl.cc index 435ae9d83f7..6cc8f2c030d 100644 --- a/source/blender/editors/render/render_opengl.cc +++ b/source/blender/editors/render/render_opengl.cc @@ -390,15 +390,7 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr) if (ibuf_result != nullptr) { if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) { - float *rectf = nullptr; - uchar *rect = nullptr; - if (ibuf_result->float_buffer.data) { - rectf = ibuf_result->float_buffer.data; - } - else { - rect = ibuf_result->byte_buffer.data; - } - BKE_image_stamp_buf(scene, camera, nullptr, rect, rectf, rr->rectx, rr->recty); + BKE_image_stamp_buf(scene, camera, nullptr, ibuf_result); } RE_render_result_rect_from_ibuf(rr, ibuf_result, oglrender->view_id); IMB_freeImBuf(ibuf_result); diff --git a/source/blender/editors/sculpt_paint/paint_image.cc b/source/blender/editors/sculpt_paint/paint_image.cc index 2371fde0d81..de831070460 100644 --- a/source/blender/editors/sculpt_paint/paint_image.cc +++ b/source/blender/editors/sculpt_paint/paint_image.cc @@ -366,11 +366,10 @@ bool paint_use_opacity_masking(const Paint *paint, const Brush *brush) void paint_brush_color_get(const Paint *paint, Brush *br, std::optional &initial_hsv_jitter, - bool color_correction, bool invert, float distance, float pressure, - const ColorManagedDisplay *display, + bool is_data, float r_color[3]) { if (invert) { @@ -396,7 +395,7 @@ void paint_brush_color_get(const Paint *paint, } } /* Gradient / Color-band colors are not considered #PROP_COLOR_GAMMA. - * Brush colors are expected to be in sRGB though. */ + * Brush colors are currently in sRGB though. */ IMB_colormanagement_scene_linear_to_srgb_v3(r_color, color_gr); } else if (color_jitter_settings) { @@ -411,8 +410,8 @@ void paint_brush_color_get(const Paint *paint, copy_v3_v3(r_color, BKE_brush_color_get(paint, br)); } } - if (color_correction) { - IMB_colormanagement_display_to_scene_linear_v3(r_color, display); + if (!is_data) { + IMB_colormanagement_srgb_to_scene_linear_v3(r_color, r_color); } } diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.cc b/source/blender/editors/sculpt_paint/paint_image_2d.cc index 44b4ef0aba9..f7a3be3b881 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.cc +++ b/source/blender/editors/sculpt_paint/paint_image_2d.cc @@ -12,12 +12,12 @@ #include "MEM_guardedalloc.h" #include "DNA_brush_types.h" -#include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_space_types.h" #include "BLI_bitmap.h" #include "BLI_listbase.h" +#include "BLI_math_color.h" #include "BLI_math_color_blend.h" #include "BLI_stack.h" #include "BLI_task.h" @@ -51,8 +51,10 @@ /* Defines and Structs */ struct BrushPainterCache { - bool use_float; /* need float imbuf? */ - bool use_color_correction; /* use color correction for float */ + bool is_float; /* need float imbuf? */ + bool is_data; /* is non-color data? */ + bool is_srgb; /* is the byte colorspace sRGB? */ + const ColorSpace *byte_colorspace; bool invert; bool is_texbrush; @@ -161,12 +163,17 @@ static BrushPainter *brush_painter_2d_new(Scene *scene, return painter; } -static void brush_painter_2d_require_imbuf( - Brush *brush, ImagePaintTile *tile, bool use_float, bool use_color_correction, bool invert) +static void brush_painter_2d_require_imbuf(Brush *brush, + ImagePaintTile *tile, + bool is_float, + bool is_data, + bool is_srgb, + const ColorSpace *byte_colorspace, + bool invert) { BrushPainterCache *cache = &tile->cache; - if (cache->use_float != use_float) { + if (cache->is_float != is_float) { if (cache->ibuf) { IMB_freeImBuf(cache->ibuf); } @@ -181,8 +188,10 @@ static void brush_painter_2d_require_imbuf( cache->lastdiameter = -1; /* force ibuf create in refresh */ } - cache->use_float = use_float; - cache->use_color_correction = use_float && use_color_correction; + cache->is_float = is_float; + cache->is_data = is_data; + cache->is_srgb = is_srgb; + cache->byte_colorspace = byte_colorspace; cache->invert = invert; cache->is_texbrush = (brush->mtex.tex && brush->image_brush_type == IMAGE_PAINT_BRUSH_TYPE_DRAW) ? @@ -380,38 +389,39 @@ static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter, static ImBuf *brush_painter_imbuf_new( BrushPainter *painter, ImagePaintTile *tile, const int size, float pressure, float distance) { - Scene *scene = painter->scene; const Paint *paint = painter->paint; Brush *brush = painter->brush; BrushPainterCache *cache = &tile->cache; - const char *display_device = scene->display_settings.display_device; - const ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device); - rctf tex_mapping = painter->tex_mapping; ImagePool *pool = painter->pool; - bool use_color_correction = cache->use_color_correction; - bool use_float = cache->use_float; - bool is_texbrush = cache->is_texbrush; + const bool is_float = cache->is_float; + const bool is_texbrush = cache->is_texbrush; int x, y, thread = 0; float brush_rgb[3]; /* allocate image buffer */ - ImBuf *ibuf = IMB_allocImBuf(size, size, 32, (use_float) ? IB_float_data : IB_byte_data); + ImBuf *ibuf = IMB_allocImBuf(size, size, 32, (is_float) ? IB_float_data : IB_byte_data); /* get brush color */ if (brush->image_brush_type == IMAGE_PAINT_BRUSH_TYPE_DRAW) { paint_brush_color_get(paint, brush, painter->initial_hsv_jitter, - use_color_correction, cache->invert, distance, pressure, - display, + cache->is_data, brush_rgb); + + if (cache->is_srgb) { + IMB_colormanagement_scene_linear_to_srgb_v3(brush_rgb, brush_rgb); + } + else if (cache->byte_colorspace) { + IMB_colormanagement_scene_linear_to_colorspace_v3(brush_rgb, cache->byte_colorspace); + } } else { brush_rgb[0] = 1.0f; @@ -429,10 +439,13 @@ static ImBuf *brush_painter_imbuf_new( brush_imbuf_tex_co(&tex_mapping, x, y, texco); const MTex *mtex = &brush->mtex; BKE_brush_sample_tex_3d(painter->paint, brush, mtex, texco, rgba, thread, pool); - /* TODO(sergey): Support texture paint color space. */ - if (!use_float) { - IMB_colormanagement_scene_linear_to_display_v3(rgba, display); + if (cache->is_srgb) { + IMB_colormanagement_scene_linear_to_srgb_v3(rgba, rgba); } + else if (cache->byte_colorspace) { + IMB_colormanagement_scene_linear_to_colorspace_v3(rgba, cache->byte_colorspace); + } + mul_v3_v3(rgba, brush_rgb); } else { @@ -440,7 +453,7 @@ static ImBuf *brush_painter_imbuf_new( rgba[3] = 1.0f; } - if (use_float) { + if (is_float) { /* write to float pixel */ float *dstf = ibuf->float_buffer.data + (y * size + x) * 4; mul_v3_v3fl(dstf, rgba, rgba[3]); /* premultiply */ @@ -470,22 +483,17 @@ static void brush_painter_imbuf_update(BrushPainter *painter, int xt, int yt) { - Scene *scene = painter->scene; const Paint *paint = painter->paint; Brush *brush = painter->brush; const MTex *mtex = &brush->mtex; BrushPainterCache *cache = &tile->cache; - const char *display_device = scene->display_settings.display_device; - const ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device); - rctf tex_mapping = painter->tex_mapping; ImagePool *pool = painter->pool; - bool use_color_correction = cache->use_color_correction; - bool use_float = cache->use_float; - bool is_texbrush = cache->is_texbrush; - bool use_texture_old = (oldtexibuf != nullptr); + const bool is_float = cache->is_float; + const bool is_texbrush = cache->is_texbrush; + const bool use_texture_old = (oldtexibuf != nullptr); int x, y, thread = 0; float brush_rgb[3]; @@ -498,12 +506,18 @@ static void brush_painter_imbuf_update(BrushPainter *painter, paint_brush_color_get(paint, brush, painter->initial_hsv_jitter, - use_color_correction, cache->invert, 0.0f, 1.0f, - display, + cache->is_data, brush_rgb); + + if (cache->is_srgb) { + IMB_colormanagement_scene_linear_to_srgb_v3(brush_rgb, brush_rgb); + } + else if (cache->byte_colorspace) { + IMB_colormanagement_scene_linear_to_colorspace_v3(brush_rgb, cache->byte_colorspace); + } } else { brush_rgb[0] = 1.0f; @@ -521,10 +535,13 @@ static void brush_painter_imbuf_update(BrushPainter *painter, if (is_texbrush) { brush_imbuf_tex_co(&tex_mapping, x, y, texco); BKE_brush_sample_tex_3d(painter->paint, brush, mtex, texco, rgba, thread, pool); - /* TODO(sergey): Support texture paint color space. */ - if (!use_float) { - IMB_colormanagement_scene_linear_to_display_v3(rgba, display); + if (cache->is_srgb) { + IMB_colormanagement_scene_linear_to_srgb_v3(rgba, rgba); } + else if (cache->byte_colorspace) { + IMB_colormanagement_scene_linear_to_colorspace_v3(rgba, cache->byte_colorspace); + } + mul_v3_v3(rgba, brush_rgb); } else { @@ -533,7 +550,7 @@ static void brush_painter_imbuf_update(BrushPainter *painter, } } - if (use_float) { + if (is_float) { /* handle float pixel */ float *bf = ibuf->float_buffer.data + (y * ibuf->x + x) * 4; float *tf = texibuf->float_buffer.data + (y * texibuf->x + x) * 4; @@ -601,7 +618,7 @@ static void brush_painter_imbuf_partial_update(BrushPainter *painter, int imbflag, destx, desty, srcx, srcy, w, h, x1, y1, x2, y2; /* create brush image buffer if it didn't exist yet */ - imbflag = (cache->use_float) ? IB_float_data : IB_byte_data; + imbflag = (cache->is_float) ? IB_float_data : IB_byte_data; if (!cache->ibuf) { cache->ibuf = IMB_allocImBuf(diameter, diameter, 32, imbflag); } @@ -1509,8 +1526,6 @@ void paint_2d_stroke(void *ps, ImagePaintState *s = static_cast(ps); BrushPainter *painter = s->painter; - const bool is_data = s->tiles[0].canvas->colormanage_flag & IMB_COLORMANAGE_IS_DATA; - s->blend = s->brush->blend; if (eraser) { s->blend = IMB_BLEND_ERASE_ALPHA; @@ -1573,13 +1588,23 @@ void paint_2d_stroke(void *ps, ImBuf *ibuf = tile->canvas; + const bool is_data = ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA; + const bool is_float = (ibuf->float_buffer.data != nullptr); + const ColorSpace *byte_colorspace = (is_float || is_data) ? nullptr : + ibuf->byte_buffer.colorspace; + const bool is_srgb = (is_float || is_data) ? + false : + IMB_colormanagement_space_is_srgb(byte_colorspace); + /* OCIO_TODO: float buffers are now always linear, so always use color correction * this should probably be changed when texture painting color space is supported */ brush_painter_2d_require_imbuf(painter->brush, tile, (ibuf->float_buffer.data != nullptr), - !is_data, + is_data, + is_srgb, + byte_colorspace, painter->cache_invert); brush_painter_2d_refresh_cache(s, painter, tile, new_coord, mval, pressure, distance, size); @@ -1861,11 +1886,13 @@ void paint_2d_bucket_fill(const bContext *C, /* First check if our image is float. If it is we should correct the color to be in linear space. */ if (!do_float) { - rgb_float_to_uchar((uchar *)&color_b, color); + blender::float3 ibuf_color = color; + IMB_colormanagement_scene_linear_to_colorspace_v3(ibuf_color, ibuf->byte_buffer.colorspace); + rgb_float_to_uchar((uchar *)&color_b, ibuf_color); *(((char *)&color_b) + 3) = strength * 255; } else { - srgb_to_linearrgb_v3_v3(color_f, color); + copy_v3_v3(color_f, color); color_f[3] = strength; } @@ -2110,7 +2137,7 @@ void paint_2d_gradient_fill( } BKE_colorband_evaluate(br->gradient, f, color_f); - linearrgb_to_srgb_v3_v3(color_f, color_f); + IMB_colormanagement_scene_linear_to_colorspace_v3(color_f, ibuf->byte_buffer.colorspace); rgba_float_to_uchar((uchar *)&color_b, color_f); ((uchar *)&color_b)[3] *= brush_alpha; IMB_blend_color_byte(ibuf->byte_buffer.data + 4 * (size_t(y_px) * ibuf->x + x_px), diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.cc b/source/blender/editors/sculpt_paint/paint_image_proj.cc index 9f60da9060d..a0e74b9b645 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.cc +++ b/source/blender/editors/sculpt_paint/paint_image_proj.cc @@ -5787,18 +5787,11 @@ static void paint_proj_stroke_ps(const bContext * /*C*/, paint_brush_color_get(paint, brush, ps_handle->initial_hsv_jitter, - false, ps->mode == BRUSH_STROKE_INVERT, distance, pressure, - nullptr, + has_data_projection_paint_image(*ps), ps->paint_color); - if (has_data_projection_paint_image(*ps)) { - copy_v3_v3(ps->paint_color_linear, ps->paint_color); - } - else { - srgb_to_linearrgb_v3_v3(ps->paint_color_linear, ps->paint_color); - } } else if (ps->brush_type == IMAGE_PAINT_BRUSH_TYPE_MASK) { ps->stencil_value = brush->weight; diff --git a/source/blender/editors/sculpt_paint/paint_intern.hh b/source/blender/editors/sculpt_paint/paint_intern.hh index 27732601cfd..fb28b8799f7 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.hh +++ b/source/blender/editors/sculpt_paint/paint_intern.hh @@ -347,12 +347,11 @@ void paint_proj_stroke_done(void *ps_handle_p); void paint_brush_color_get(const Paint *paint, Brush *br, std::optional &initial_hsv_jitter, - bool color_correction, bool invert, float distance, float pressure, - const ColorManagedDisplay *display, - float r_color[3]); + bool is_data, + float r_color[3] /* In scene linear colorspace. */); bool paint_use_opacity_masking(const Paint *paint, const Brush *brush); void paint_brush_init_tex(Brush *brush); void paint_brush_exit_tex(Brush *brush); diff --git a/source/blender/editors/space_image/image_draw.cc b/source/blender/editors/space_image/image_draw.cc index e1bbbb6a07b..b98080a24ee 100644 --- a/source/blender/editors/space_image/image_draw.cc +++ b/source/blender/editors/space_image/image_draw.cc @@ -251,7 +251,7 @@ void ED_image_draw_info(Scene *scene, rgba, rgba, &scene->view_settings, &scene->display_settings); } - SNPRINTF_UTF8(str, " | CM R:%-.4f G:%-.4f B:%-.4f", rgba[0], rgba[1], rgba[2]); + SNPRINTF_UTF8(str, " | Display R:%-.4f G:%-.4f B:%-.4f", rgba[0], rgba[1], rgba[2]); BLF_position(blf_mono_font, dx, dy, 0); BLF_draw(blf_mono_font, str, sizeof(str)); dx += BLF_width(blf_mono_font, str, sizeof(str)); diff --git a/source/blender/editors/space_node/node_socket_tooltip.cc b/source/blender/editors/space_node/node_socket_tooltip.cc index f4c998ecea0..21422438cee 100644 --- a/source/blender/editors/space_node/node_socket_tooltip.cc +++ b/source/blender/editors/space_node/node_socket_tooltip.cc @@ -416,7 +416,6 @@ class SocketTooltipBuilder { this->build_tooltip_value_and_type_oneline(value_str, TIP_("Float Color")); this->add_space(); - this->add_text_field_mono(TIP_("Display:"), UI_TIP_LC_NORMAL); bool is_gamma = false; const ColorManagedDisplay *display = nullptr; if (but_) { diff --git a/source/blender/imbuf/IMB_imbuf.hh b/source/blender/imbuf/IMB_imbuf.hh index 92b35241747..6e13bee275f 100644 --- a/source/blender/imbuf/IMB_imbuf.hh +++ b/source/blender/imbuf/IMB_imbuf.hh @@ -24,11 +24,6 @@ struct GSet; struct ImageFormatData; struct Stereo3dFormat; -namespace blender::ocio { -class Display; -} // namespace blender::ocio -using ColorManagedDisplay = blender::ocio::Display; - /** * Module init/exit. */ @@ -470,53 +465,19 @@ void IMB_rectfill(ImBuf *drect, const float col[4]); /** * Blend pixels of image area with solid color. * - * For images with `uchar` buffer use color matching image color-space. - * For images with float buffer use color display color-space. - * If display color-space can not be referenced, use color in SRGB color-space. - * * \param ibuf: an image to be filled with color. It must be 4 channel image. - * \param col: RGBA color. - * \param x1, y1, x2, y2: (x1, y1) defines starting point of the rectangular area to be filled, - * (x2, y2) is the end point. Note that values are allowed to be loosely ordered, which means that - * x2 is allowed to be lower than x1, as well as y2 is allowed to be lower than y1. No matter the - * order the area between x1 and x2, and y1 and y2 is filled. - * \param display: color-space reference for display space. + * \param scene_linear_color: RGBA color in scene linear colorspace. For byte buffers, this is + * converted to the byte buffer colorspace. + * \param x1, y1, x2, y2: (x1, y1) defines starting point + * of the rectangular area to be filled, (x2, y2) is the end point. Note that values are allowed to + * be loosely ordered, which means that x2 is allowed to be lower than x1, as well as y2 is allowed + * to be lower than y1. No matter the order the area between x1 and x2, and y1 and y2 is filled. + * \param colorspace: color-space reference for display space. */ -void IMB_rectfill_area(ImBuf *ibuf, - const float col[4], - int x1, - int y1, - int x2, - int y2, - const ColorManagedDisplay *display); -/** - * Replace pixels of image area with solid color. - * \param ibuf: an image to be filled with color. It must be 4 channel image. - * \param col: RGBA color, which is assigned directly to both byte (via scaling) and float buffers. - * \param x1, y1, x2, y2: (x1, y1) defines starting point of the rectangular area to be filled, - * (x2, y2) is the end point. Note that values are allowed to be loosely ordered, which means that - * x2 is allowed to be lower than x1, as well as y2 is allowed to be lower than y1. No matter the - * order the area between x1 and x2, and y1 and y2 is filled. - */ -void IMB_rectfill_area_replace( - const ImBuf *ibuf, const float col[4], int x1, int y1, int x2, int y2); +void IMB_rectfill_area( + ImBuf *ibuf, const float scene_linear_color[4], int x1, int y1, int x2, int y2); void IMB_rectfill_alpha(ImBuf *ibuf, float value); -/** - * This should not be here, really, - * we needed it for operating on render data, #IMB_rectfill_area calls it. - */ -void buf_rectfill_area(unsigned char *rect, - float *rectf, - int width, - int height, - const float col[4], - const ColorManagedDisplay *display, - int x1, - int y1, - int x2, - int y2); - /** * Exported for image tools in blender, to quickly allocate 32 bits rect. */ diff --git a/source/blender/imbuf/intern/rectop.cc b/source/blender/imbuf/intern/rectop.cc index 6acb3f9e910..9561e92b477 100644 --- a/source/blender/imbuf/intern/rectop.cc +++ b/source/blender/imbuf/intern/rectop.cc @@ -1008,65 +1008,19 @@ void IMB_rectfill(ImBuf *drect, const float col[4]) } } -void IMB_rectfill_area_replace( - const ImBuf *ibuf, const float col[4], int x1, int y1, int x2, int y2) +void IMB_rectfill_area( + ImBuf *ibuf, const float scene_linear_color[4], int x1, int y1, int x2, int y2) { - /* Sanity checks. */ - BLI_assert(ibuf->channels == 4); - - if (ibuf->channels != 4) { + if (!ibuf) { return; } - int width = ibuf->x; - int height = ibuf->y; - CLAMP(x1, 0, width); - CLAMP(x2, 0, width); - CLAMP(y1, 0, height); - CLAMP(y2, 0, height); + uchar *rect = ibuf->byte_buffer.data; + float *rectf = ibuf->float_buffer.data; + const int width = ibuf->x; + const int height = ibuf->y; - if (x1 > x2) { - std::swap(x1, x2); - } - if (y1 > y2) { - std::swap(y1, y2); - } - if (x1 == x2 || y1 == y2) { - return; - } - - const uchar col_char[4] = { - uchar(col[0] * 255), uchar(col[1] * 255), uchar(col[2] * 255), uchar(col[3] * 255)}; - - for (int y = y1; y < y2; y++) { - for (int x = x1; x < x2; x++) { - size_t offset = size_t(ibuf->x) * y * 4 + 4 * x; - - if (ibuf->byte_buffer.data) { - uchar *rrect = ibuf->byte_buffer.data + offset; - memcpy(rrect, col_char, sizeof(uchar[4])); - } - - if (ibuf->float_buffer.data) { - float *rrectf = ibuf->float_buffer.data + offset; - memcpy(rrectf, col, sizeof(float[4])); - } - } - } -} - -void buf_rectfill_area(uchar *rect, - float *rectf, - int width, - int height, - const float col[4], - const ColorManagedDisplay *display, - int x1, - int y1, - int x2, - int y2) -{ - if ((!rect && !rectf) || (!col) || col[3] == 0.0f) { + if ((!rect && !rectf) || scene_linear_color[3] == 0.0f) { return; } @@ -1089,7 +1043,7 @@ void buf_rectfill_area(uchar *rect, const int y_span = y2 - y1; /* Alpha. */ - const float a = col[3]; + const float a = scene_linear_color[3]; /* Alpha inverted. */ const float ai = 1 - a; /* Alpha, inverted, ai/255.0 - Convert char to float at the same time. */ @@ -1102,6 +1056,15 @@ void buf_rectfill_area(uchar *rect, const int alphaint = unit_float_to_uchar_clamp(a); + float col[3]; + copy_v3_v3(col, scene_linear_color); + if (ibuf->byte_buffer.colorspace) { + IMB_colormanagement_scene_linear_to_colorspace_v3(col, ibuf->byte_buffer.colorspace); + } + else { + IMB_colormanagement_scene_linear_to_srgb_v3(col, scene_linear_color); + } + if (a == 1.0f) { chr = unit_float_to_uchar_clamp(col[0]); chg = unit_float_to_uchar_clamp(col[1]); @@ -1135,32 +1098,23 @@ void buf_rectfill_area(uchar *rect, } if (rectf) { - float col_conv[4]; float *pixel; - if (display) { - copy_v4_v4(col_conv, col); - IMB_colormanagement_display_to_scene_linear_v3(col_conv, display); - } - else { - srgb_to_linearrgb_v4(col_conv, col); - } - for (int j = 0; j < y_span; j++) { pixel = rectf + (4 * (((size_t(y1) + j) * size_t(width)) + size_t(x1))); for (int i = 0; i < x_span; i++) { BLI_assert(pixel >= rectf && pixel < rectf + (4 * (size_t(width) * size_t(height)))); if (a == 1.0f) { - pixel[0] = col_conv[0]; - pixel[1] = col_conv[1]; - pixel[2] = col_conv[2]; + pixel[0] = scene_linear_color[0]; + pixel[1] = scene_linear_color[1]; + pixel[2] = scene_linear_color[2]; pixel[3] = 1.0f; } else { float alphatest; - pixel[0] = (col_conv[0] * a) + (pixel[0] * ai); - pixel[1] = (col_conv[1] * a) + (pixel[1] * ai); - pixel[2] = (col_conv[2] * a) + (pixel[2] * ai); + pixel[0] = (scene_linear_color[0] * a) + (pixel[0] * ai); + pixel[1] = (scene_linear_color[1] * a) + (pixel[1] * ai); + pixel[2] = (scene_linear_color[2] * a) + (pixel[2] * ai); pixel[3] = (alphatest = (pixel[3] + a)) < 1.0f ? alphatest : 1.0f; } pixel += 4; @@ -1169,29 +1123,6 @@ void buf_rectfill_area(uchar *rect, } } -void IMB_rectfill_area(ImBuf *ibuf, - const float col[4], - int x1, - int y1, - int x2, - int y2, - const ColorManagedDisplay *display) -{ - if (!ibuf) { - return; - } - buf_rectfill_area(ibuf->byte_buffer.data, - ibuf->float_buffer.data, - ibuf->x, - ibuf->y, - col, - display, - x1, - y1, - x2, - y2); -} - void IMB_rectfill_alpha(ImBuf *ibuf, const float value) { size_t i; diff --git a/source/blender/makesrna/intern/rna_rna.cc b/source/blender/makesrna/intern/rna_rna.cc index 9c3377cccb1..94f7006b281 100644 --- a/source/blender/makesrna/intern/rna_rna.cc +++ b/source/blender/makesrna/intern/rna_rna.cc @@ -81,8 +81,8 @@ const EnumPropertyItem rna_enum_property_type_items[] = { {PROP_FREQUENCY, "FREQUENCY", 0, "Frequency", ""} #define RNA_ENUM_PROPERTY_SUBTYPE_NUMBER_ARRAY_ITEMS \ - {PROP_COLOR, "COLOR", 0, "Linear Color", "Color in the linear space"}, \ - {PROP_TRANSLATION, "TRANSLATION", 0, "Translation", "Color in the gamma corrected space"}, \ + {PROP_COLOR, "COLOR", 0, "Linear Color", "Color in the scene linear working color space"}, \ + {PROP_TRANSLATION, "TRANSLATION", 0, "Translation", ""}, \ {PROP_DIRECTION, "DIRECTION", 0, "Direction", ""}, \ {PROP_VELOCITY, "VELOCITY", 0, "Velocity", ""}, \ {PROP_ACCELERATION, "ACCELERATION", 0, "Acceleration", ""}, \ @@ -92,7 +92,7 @@ const EnumPropertyItem rna_enum_property_type_items[] = { {PROP_AXISANGLE, "AXISANGLE", 0, "Axis-Angle", "Angle and axis to rotate around"}, \ {PROP_XYZ, "XYZ", 0, "XYZ", ""}, \ {PROP_XYZ_LENGTH, "XYZ_LENGTH", 0, "XYZ Length", ""}, \ - {PROP_COLOR_GAMMA, "COLOR_GAMMA", 0, "Gamma-Corrected Color", ""}, \ + {PROP_COLOR_GAMMA, "COLOR_GAMMA", 0, "sRGB Color", "Color in sRGB color space (mainly for user interface colors)"}, \ {PROP_COORDS, "COORDINATES", 0, "Coordinates", ""}, \ /* Boolean. */ \ {PROP_LAYER, "LAYER", 0, "Layer", ""}, \ diff --git a/source/blender/python/generic/blf_py_api.cc b/source/blender/python/generic/blf_py_api.cc index 69c9bd51044..51e08b6d3b9 100644 --- a/source/blender/python/generic/blf_py_api.cc +++ b/source/blender/python/generic/blf_py_api.cc @@ -34,7 +34,6 @@ struct BPyBLFImBufContext { PyObject_HEAD /* Required Python macro. */ PyObject *py_imbuf; - const ColorManagedDisplay *display; int fontid; BLFBufferState *buffer_state; @@ -532,7 +531,7 @@ static PyObject *py_blf_bind_imbuf_enter(BPyBLFImBufContext *self) ibuf->byte_buffer.data, ibuf->x, ibuf->y, - self->display); + ibuf->byte_buffer.colorspace); self->buffer_state = buffer_state; Py_RETURN_NONE; @@ -654,7 +653,7 @@ static PyTypeObject BPyBLFImBufContext_Type = { PyDoc_STRVAR( /* Wrap. */ py_blf_bind_imbuf_doc, - ".. method:: bind_imbuf(fontid, image, display_name=None)\n" + ".. method:: bind_imbuf(fontid, image)\n" "\n" " Context manager to draw text into an image buffer instead of the GPU's context.\n" "\n" @@ -663,8 +662,6 @@ PyDoc_STRVAR( " :type fontid: int\n" " :arg imbuf: The image to draw into.\n" " :type imbuf: :class:`imbuf.types.ImBuf`\n" - " :arg display_name: The color management display name to use or None.\n" - " :type display_name: str | None\n" " :return: The BLF ImBuf context manager.\n" " :rtype: BLFImBufContext\n"); @@ -697,32 +694,12 @@ static PyObject *py_blf_bind_imbuf(PyObject * /*self*/, PyObject *args, PyObject return nullptr; } - const ColorManagedDisplay *display = nullptr; - if (display_name) { - display = IMB_colormanagement_display_get_named(display_name); - if (UNLIKELY(display == nullptr)) { - std::string display_names_all; - display_names_all.reserve(1024); - const char *ex = nullptr; - /* 1 based index. */ - for (int i = 1; (ex = IMB_colormanagement_display_get_indexed_name(i)); i++) { - if (i > 1) { - display_names_all += ", "; - } - display_names_all += ex; - } - PyErr_Format(PyExc_ValueError, - "bind_imbuf: color management \"%s\" not found in [%s]", - display_name, - display_names_all.c_str()); - return nullptr; - } - } + /* Display name is ignored, it is only kept for backwards compatibility. This should + * always have been the image buffer byte colorspace rather than a display. */ BPyBLFImBufContext *ret = PyObject_GC_New(BPyBLFImBufContext, &BPyBLFImBufContext_Type); ret->py_imbuf = Py_NewRef(py_imbuf); - ret->display = display; ret->fontid = fontid; ret->buffer_state = nullptr; diff --git a/source/blender/render/intern/pipeline.cc b/source/blender/render/intern/pipeline.cc index 6284f643931..66300b23cd5 100644 --- a/source/blender/render/intern/pipeline.cc +++ b/source/blender/render/intern/pipeline.cc @@ -1425,10 +1425,7 @@ static void renderresult_stampinfo(Render *re) BKE_image_stamp_buf(re->scene, ob_camera_eval, (re->scene->r.stamp & R_STAMP_STRIPMETA) ? rres.stamp_data : nullptr, - rres.ibuf->byte_buffer.data, - rres.ibuf->float_buffer.data, - rres.rectx, - rres.recty); + rres.ibuf); } RE_ReleaseResultImage(re); diff --git a/source/blender/sequencer/intern/effects/vse_effect_text.cc b/source/blender/sequencer/intern/effects/vse_effect_text.cc index b4934c1d0b7..27117ee80fc 100644 --- a/source/blender/sequencer/intern/effects/vse_effect_text.cc +++ b/source/blender/sequencer/intern/effects/vse_effect_text.cc @@ -575,7 +575,6 @@ static void text_draw(const char *text_ptr, const TextVarsRuntime *runtime, floa static rcti draw_text_outline(const RenderData *context, const TextVars *data, const TextVarsRuntime *runtime, - const ColorManagedDisplay *display, ImBuf *out) { /* Outline width of 1.0 maps to half of text line height. */ @@ -591,7 +590,12 @@ static rcti draw_text_outline(const RenderData *context, /* Draw white text into temporary buffer. */ const size_t pixel_count = size_t(size.x) * size.y; Array tmp_buf(pixel_count, uchar4(0)); - BLF_buffer(runtime->font, nullptr, (uchar *)tmp_buf.data(), size.x, size.y, display); + BLF_buffer(runtime->font, + nullptr, + (uchar *)tmp_buf.data(), + size.x, + size.y, + out->byte_buffer.colorspace); text_draw(data->text_ptr, runtime, float4(1.0f)); @@ -691,7 +695,8 @@ static rcti draw_text_outline(const RenderData *context, } } }); - BLF_buffer(runtime->font, nullptr, out->byte_buffer.data, size.x, size.y, display); + BLF_buffer( + runtime->font, nullptr, out->byte_buffer.data, size.x, size.y, out->byte_buffer.colorspace); return outline_rect; } @@ -1027,8 +1032,6 @@ static ImBuf *do_text_effect(const RenderData *context, ImBuf *out = prepare_effect_imbufs(context, nullptr, nullptr, false); TextVars *data = static_cast(strip->effectdata); - const char *display_device = context->scene->display_settings.display_device; - const ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device); const FontFlags font_flags = ((data->flag & SEQ_TEXT_BOLD) ? BLF_BOLD : BLF_NONE) | ((data->flag & SEQ_TEXT_ITALIC) ? BLF_ITALIC : BLF_NONE); @@ -1044,8 +1047,8 @@ static ImBuf *do_text_effect(const RenderData *context, TextVarsRuntime *runtime = text_effect_calc_runtime(strip, font, {out->x, out->y}); data->runtime = runtime; - rcti outline_rect = draw_text_outline(context, data, runtime, display, out); - BLF_buffer(font, nullptr, out->byte_buffer.data, out->x, out->y, display); + rcti outline_rect = draw_text_outline(context, data, runtime, out); + BLF_buffer(font, nullptr, out->byte_buffer.data, out->x, out->y, out->byte_buffer.colorspace); text_draw(data->text_ptr, runtime, data->color); BLF_buffer(font, nullptr, nullptr, 0, 0, nullptr); BLF_disable(font, font_flags);