From 663c9082db4dfe43bb329a09fd5b93a6ba99fdb6 Mon Sep 17 00:00:00 2001 From: Sam McCall Date: Sat, 22 Mar 2025 20:11:23 +0100 Subject: [PATCH] render: dim and brighten using linear rgb interpolation Adds setting tweak.dim-amount, similar to bold-text-in-bright-amount. Closes #2006 --- CHANGELOG.md | 6 +++++ config.c | 4 ++++ config.h | 4 ++++ doc/foot.ini.5.scd | 11 +++++---- hsl.c | 35 ----------------------------- hsl.h | 1 - render.c | 56 +++++++++++++++++++++++++--------------------- 7 files changed, 51 insertions(+), 66 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ed4bd7a..671b6dad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,12 @@ ### Changed * UTF-8 error recovery now discards fewer bytes. +* Auto-calculated dimmed and brightened colors (e.g. when custom dim + colors has not configured) is now done by linear RGB interpolation, + rather than converting to HSL and adjusting the luminance + ([#2006][2006]). + +[2006]: https://codeberg.org/dnkl/foot/issues/2006 ### Deprecated diff --git a/config.c b/config.c index 222b1b60..a8cdb34a 100644 --- a/config.c +++ b/config.c @@ -2759,6 +2759,9 @@ parse_section_tweak(struct context *ctx) else if (streq(key, "sixel")) return value_to_bool(ctx, &conf->tweak.sixel); + else if (streq(key, "dim-amount")) + return value_to_float(ctx, &conf->dim.amount); + else if (streq(key, "bold-text-in-bright-amount")) return value_to_float(ctx, &conf->bold_in_bright.amount); @@ -3288,6 +3291,7 @@ config_load(struct config *conf, const char *conf_path, .resize_by_cells = true, .resize_keep_grid = true, .resize_delay_ms = 100, + .dim = { .amount = 1.5 }, .bold_in_bright = { .enabled = false, .palette_based = false, diff --git a/config.h b/config.h index fb019d90..a08fae31 100644 --- a/config.h +++ b/config.h @@ -155,6 +155,10 @@ struct config { uint16_t resize_delay_ms; + struct { + float amount; + } dim; + struct { bool enabled; bool palette_based; diff --git a/doc/foot.ini.5.scd b/doc/foot.ini.5.scd index 7fad2b9c..2a065a0c 100644 --- a/doc/foot.ini.5.scd +++ b/doc/foot.ini.5.scd @@ -396,7 +396,7 @@ empty string to be set, but it must be quoted: *KEY=""*) *bold-text-in-bright* Semi-boolean. When enabled, bold text is rendered in a brighter color (in addition to using a bold font). The color is brightened - by increasing its luminance. + by blending it with white. If set to *palette-based*, rather than a simple *yes|true*, colors matching one of the 8 regular palette colors will be brightened @@ -986,8 +986,8 @@ can configure the background transparency with the _alpha_ option. an entry in the color palette. Applications emit them by combining a color value, and a "dim" attribute. - By default, foot implements this by reducing the luminance of the - current color. This is a generic approach that applies to both + By default, foot implements this by blending the current color + with black. This is a generic approach that applies to both colors from the 256-color palette, as well as 24-bit RGB colors. You can change this behavior by setting the *dimN* options. When @@ -999,7 +999,7 @@ can configure the background transparency with the _alpha_ option. the corresponding *regularN* color will be used. If the current color does not match any known color, it is dimmed - by reducing the luminance (i.e. the same behavior as if the *dimN* + by blending with black (i.e. the same behavior as if the *dimN* options are unconfigured). 24-bit RGB colors will typically fall into this category. @@ -1940,6 +1940,9 @@ any of these options. Boolean. When enabled, foot will process sixel images. Default: _yes_ +*dim-amount* + Amount by which dimmed text is darkened. Default: _1.5_. + *bold-text-in-bright-amount* Amount by which bold fonts are brightened when *bold-text-in-bright* is set to *yes* (the *palette-based* variant diff --git a/hsl.c b/hsl.c index d5d00e67..1a8c919e 100644 --- a/hsl.c +++ b/hsl.c @@ -2,41 +2,6 @@ #include -#include "util.h" - -void -rgb_to_hsl(uint32_t rgb, int *hue, int *sat, int *lum) -{ - double r = (double)((rgb >> 16) & 0xff) / 255.; - double g = (double)((rgb >> 8) & 0xff) / 255.; - double b = (double)((rgb >> 0) & 0xff) / 255.; - - double x_max = max(max(r, g), b); - double x_min = min(min(r, g), b); - double V = x_max; - - double C = x_max - x_min; - double L = (x_max + x_min) / 2.; - - *lum = 100 * L; - - if (C == 0.0) - *hue = 0; - else if (V == r) - *hue = 60. * (0. + (g - b) / C); - else if (V == g) - *hue = 60. * (2. + (b - r) / C); - else if (V == b) - *hue = 60. * (4. + (r - g) / C); - if (*hue < 0) - *hue += 360; - - double S = C == 0.0 - ? 0 - : C / (1. - fabs(2. * L - 1.)); - *sat = 100 * S; -} - uint32_t hsl_to_rgb(int hue, int sat, int lum) { diff --git a/hsl.h b/hsl.h index 2a46c117..1aaf7e66 100644 --- a/hsl.h +++ b/hsl.h @@ -2,5 +2,4 @@ #include -void rgb_to_hsl(uint32_t rgb, int *hue, int *sat, int *lum); uint32_t hsl_to_rgb(int hue, int sat, int lum); diff --git a/render.c b/render.c index 4975394f..d2202468 100644 --- a/render.c +++ b/render.c @@ -34,7 +34,6 @@ #include "config.h" #include "cursor-shape.h" #include "grid.h" -#include "hsl.h" #include "ime.h" #include "quirks.h" #include "search.h" @@ -271,13 +270,23 @@ color_hex_to_pixman(uint32_t color, bool srgb) return color_hex_to_pixman_with_alpha(color, 0xffff, srgb); } +static inline int i_lerp(int from, int to, float t) { + return from + (to - from) * t; +} + static inline uint32_t -color_decrease_luminance(uint32_t color) +color_blend_towards(uint32_t from, uint32_t to, float amount) { - uint32_t alpha = color & 0xff000000; - int hue, sat, lum; - rgb_to_hsl(color, &hue, &sat, &lum); - return alpha | hsl_to_rgb(hue, sat, lum / 1.5); + if (unlikely(amount == 0)) + return from; + float t = 1 - 1/amount; + + uint32_t alpha = from & 0xff000000; + uint8_t r = i_lerp((from>>16)&0xff, (to>>16)&0xff, t); + uint8_t g = i_lerp((from>>8)&0xff, (to>>8)&0xff, t); + uint8_t b = i_lerp((from>>0)&0xff, (to>>0)&0xff, t); + + return alpha | (r<<16) | (g<<8) | (b<<0); } static inline uint32_t @@ -286,25 +295,24 @@ color_dim(const struct terminal *term, uint32_t color) const struct config *conf = term->conf; const uint8_t custom_dim = conf->colors.use_custom.dim; - if (likely(custom_dim == 0)) - return color_decrease_luminance(color); + if (unlikely(custom_dim != 0)) { + for (size_t i = 0; i < 8; i++) { + if (((custom_dim >> i) & 1) == 0) + continue; - for (size_t i = 0; i < 8; i++) { - if (((custom_dim >> i) & 1) == 0) - continue; + if (term->colors.table[0 + i] == color) { + /* "Regular" color, return the corresponding "dim" */ + return conf->colors.dim[i]; + } - if (term->colors.table[0 + i] == color) { - /* "Regular" color, return the corresponding "dim" */ - return conf->colors.dim[i]; - } - - else if (term->colors.table[8 + i] == color) { - /* "Bright" color, return the corresponding "regular" */ - return term->colors.table[i]; + else if (term->colors.table[8 + i] == color) { + /* "Bright" color, return the corresponding "regular" */ + return term->colors.table[i]; + } } } - return color_decrease_luminance(color); + return color_blend_towards(color, 0x00000000, conf->dim.amount); } static inline uint32_t @@ -322,11 +330,7 @@ color_brighten(const struct terminal *term, uint32_t color) return color; } - int hue, sat, lum; - rgb_to_hsl(color, &hue, &sat, &lum); - - lum = (int)roundf(lum * term->conf->bold_in_bright.amount); - return hsl_to_rgb(hue, sat, min(lum, 100)); + return color_blend_towards(color, 0x00ffffff, term->conf->bold_in_bright.amount); } static void @@ -798,7 +802,7 @@ render_cell(struct terminal *term, pixman_image_t *pix, _fg = color_brighten(term, _fg); if (cell->attrs.blink && term->blink.state == BLINK_OFF) - _fg = color_decrease_luminance(_fg); + _fg = color_blend_towards(_fg, 0x00000000, term->conf->dim.amount); const bool gamma_correct = render_do_linear_blending(term); pixman_color_t fg = color_hex_to_pixman(_fg, gamma_correct);