mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-04-13 08:21:03 -04:00
generate 256 palette
This commit is contained in:
parent
c291194a4e
commit
cc0a4ba756
7 changed files with 202 additions and 2 deletions
97
config.c
97
config.c
|
|
@ -28,6 +28,7 @@
|
|||
#include "tokenize.h"
|
||||
#include "util.h"
|
||||
#include "xmalloc.h"
|
||||
#include "lab.h"
|
||||
#include "xsnprintf.h"
|
||||
|
||||
static const uint32_t default_foreground = 0xffffff;
|
||||
|
|
@ -1156,6 +1157,9 @@ parse_section_main(struct context *ctx)
|
|||
return true;
|
||||
}
|
||||
|
||||
else if (streq(key, "generate-256-palette"))
|
||||
return value_to_bool(ctx, &conf->generate_256_palette);
|
||||
|
||||
else if (streq(key, "uppercase-regex-insert"))
|
||||
return value_to_bool(ctx, &conf->uppercase_regex_insert);
|
||||
|
||||
|
|
@ -1410,6 +1414,7 @@ parse_color_theme(struct context *ctx, struct color_theme *theme)
|
|||
size_t key_len = strlen(key);
|
||||
uint8_t last_digit = (unsigned char)key[key_len - 1] - '0';
|
||||
uint32_t *color = NULL;
|
||||
int table_index = -1;
|
||||
|
||||
if (isdigit(key[0])) {
|
||||
unsigned long index;
|
||||
|
|
@ -1420,13 +1425,18 @@ parse_color_theme(struct context *ctx, struct color_theme *theme)
|
|||
return false;
|
||||
}
|
||||
color = &theme->table[index];
|
||||
table_index = (int)index;
|
||||
}
|
||||
|
||||
else if (key_len == 8 && str_has_prefix(key, "regular") && last_digit < 8)
|
||||
else if (key_len == 8 && str_has_prefix(key, "regular") && last_digit < 8) {
|
||||
color = &theme->table[last_digit];
|
||||
table_index = last_digit;
|
||||
}
|
||||
|
||||
else if (key_len == 7 && str_has_prefix(key, "bright") && last_digit < 8)
|
||||
else if (key_len == 7 && str_has_prefix(key, "bright") && last_digit < 8) {
|
||||
color = &theme->table[8 + last_digit];
|
||||
table_index = 8 + last_digit;
|
||||
}
|
||||
|
||||
else if (key_len == 4 && str_has_prefix(key, "dim") && last_digit < 8) {
|
||||
if (!value_to_color(ctx, &theme->dim[last_digit], false))
|
||||
|
|
@ -1586,6 +1596,10 @@ parse_color_theme(struct context *ctx, struct color_theme *theme)
|
|||
return false;
|
||||
|
||||
*color = color_value;
|
||||
|
||||
if (table_index >= 0)
|
||||
theme->table_mask[table_index / 32] |= 1u << (table_index % 32);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -3432,6 +3446,75 @@ config_font_list_clone(struct config_font_list *dst,
|
|||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
table_mask_is_set(const uint32_t *mask, unsigned idx)
|
||||
{
|
||||
return (mask[idx / 32] >> (idx % 32)) & 1;
|
||||
}
|
||||
|
||||
static void
|
||||
generate_256_palette(uint32_t *table, const uint32_t *mask,
|
||||
uint32_t bg, uint32_t fg)
|
||||
{
|
||||
/*
|
||||
* Generate colors 16-255 by interpolating in CIELAB space.
|
||||
*
|
||||
* Corner mapping for trilinear interpolation:
|
||||
* bg -> (r=0, g=0, b=0)
|
||||
* palette[1] -> (r=1, g=0, b=0) red
|
||||
* palette[2] -> (r=0, g=1, b=0) green
|
||||
* palette[3] -> (r=1, g=1, b=0) yellow
|
||||
* palette[4] -> (r=0, g=0, b=1) blue
|
||||
* palette[5] -> (r=1, g=0, b=1) magenta
|
||||
* palette[6] -> (r=0, g=1, b=1) cyan
|
||||
* fg -> (r=1, g=1, b=1)
|
||||
*/
|
||||
struct lab base8_lab[8];
|
||||
for (int i = 0; i < 8; i++)
|
||||
base8_lab[i] = lab_from_rgb(table[i]);
|
||||
|
||||
struct lab bg_lab = lab_from_rgb(bg);
|
||||
struct lab fg_lab = lab_from_rgb(fg);
|
||||
|
||||
/* Colors 16-231: 6x6x6 color cube via trilinear interpolation */
|
||||
unsigned idx = 16;
|
||||
for (unsigned ri = 0; ri < 6; ri++) {
|
||||
float tr = (float)ri / 5.0f;
|
||||
|
||||
/* Interpolate along R axis (4 edges) */
|
||||
struct lab c0 = lab_lerp(tr, bg_lab, base8_lab[1]);
|
||||
struct lab c1 = lab_lerp(tr, base8_lab[2], base8_lab[3]);
|
||||
struct lab c2 = lab_lerp(tr, base8_lab[4], base8_lab[5]);
|
||||
struct lab c3 = lab_lerp(tr, base8_lab[6], fg_lab);
|
||||
|
||||
for (unsigned gi = 0; gi < 6; gi++) {
|
||||
float tg = (float)gi / 5.0f;
|
||||
|
||||
/* Interpolate along G axis (2 edges) */
|
||||
struct lab c4 = lab_lerp(tg, c0, c1);
|
||||
struct lab c5 = lab_lerp(tg, c2, c3);
|
||||
|
||||
for (unsigned bi = 0; bi < 6; bi++) {
|
||||
if (!table_mask_is_set(mask, idx)) {
|
||||
/* Interpolate along B axis */
|
||||
struct lab c6 = lab_lerp((float)bi / 5.0f, c4, c5);
|
||||
table[idx] = lab_to_rgb(c6);
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Colors 232-255: grayscale ramp from bg to fg */
|
||||
for (unsigned i = 0; i < 24; i++) {
|
||||
if (!table_mask_is_set(mask, idx)) {
|
||||
float t = (float)(i + 1) / 25.0f;
|
||||
table[idx] = lab_to_rgb(lab_lerp(t, bg_lab, fg_lab));
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
config_load(struct config *conf, const char *conf_path,
|
||||
user_notifications_t *initial_user_notifications,
|
||||
|
|
@ -3528,6 +3611,7 @@ config_load(struct config *conf, const char *conf_path,
|
|||
},
|
||||
},
|
||||
.initial_color_theme = COLOR_THEME_DARK,
|
||||
.generate_256_palette = true,
|
||||
.cursor = {
|
||||
.style = CURSOR_BLOCK,
|
||||
.unfocused_style = CURSOR_UNFOCUSED_HOLLOW,
|
||||
|
|
@ -3715,6 +3799,15 @@ config_load(struct config *conf, const char *conf_path,
|
|||
if (!config_override_apply(conf, overrides, errors_are_fatal))
|
||||
ret = !errors_are_fatal;
|
||||
|
||||
if (conf->generate_256_palette) {
|
||||
generate_256_palette(
|
||||
conf->colors_dark.table, conf->colors_dark.table_mask,
|
||||
conf->colors_dark.bg, conf->colors_dark.fg);
|
||||
generate_256_palette(
|
||||
conf->colors_light.table, conf->colors_light.table_mask,
|
||||
conf->colors_light.bg, conf->colors_light.fg);
|
||||
}
|
||||
|
||||
if (ret && conf->fonts[0].count == 0) {
|
||||
struct config_font font;
|
||||
if (!config_font_parse("monospace", &font)) {
|
||||
|
|
|
|||
2
config.h
2
config.h
|
|
@ -137,6 +137,7 @@ struct color_theme {
|
|||
uint32_t flash;
|
||||
uint32_t flash_alpha;
|
||||
uint32_t table[256];
|
||||
uint32_t table_mask[8]; /* 256-bit mask tracking user-set palette entries */
|
||||
uint16_t alpha;
|
||||
uint32_t selection_fg;
|
||||
uint32_t selection_bg;
|
||||
|
|
@ -332,6 +333,7 @@ struct config {
|
|||
struct color_theme colors_dark;
|
||||
struct color_theme colors_light;
|
||||
enum which_color_theme initial_color_theme;
|
||||
bool generate_256_palette;
|
||||
|
||||
struct {
|
||||
enum cursor_style style;
|
||||
|
|
|
|||
|
|
@ -383,6 +383,17 @@ empty string to be set, but it must be quoted: *KEY=""*)
|
|||
|
||||
Default: _1_
|
||||
|
||||
*generate-256-palette*
|
||||
Boolean. When enabled, the extended 256-color palette (colors
|
||||
16-255) is generated by interpolating from the base 16 colors,
|
||||
foreground, and background using the CIELAB color space. This
|
||||
makes the 256-color palette harmonize with custom color schemes
|
||||
instead of using the fixed standard values.
|
||||
|
||||
Palette entries explicitly set by the user are not overwritten.
|
||||
|
||||
Default: _yes_
|
||||
|
||||
*initial-window-size-pixels*
|
||||
Initial window width and height in _pixels_ (subject to output
|
||||
scaling), in the form _WIDTHxHEIGHT_. The height _includes_ the
|
||||
|
|
|
|||
1
foot.ini
1
foot.ini
|
|
@ -25,6 +25,7 @@
|
|||
# gamma-correct-blending=no
|
||||
|
||||
# initial-color-theme=dark
|
||||
# generate-256-palette=yes
|
||||
# initial-window-size-pixels=700x500 # Or,
|
||||
# initial-window-size-chars=<COLSxROWS>
|
||||
# initial-window-mode=windowed
|
||||
|
|
|
|||
79
lab.c
Normal file
79
lab.c
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
#include "lab.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
struct lab
|
||||
lab_from_rgb(uint32_t rgb)
|
||||
{
|
||||
/* Extract and normalize sRGB components */
|
||||
float r = ((rgb >> 16) & 0xff) / 255.0f;
|
||||
float g = ((rgb >> 8) & 0xff) / 255.0f;
|
||||
float b = (rgb & 0xff) / 255.0f;
|
||||
|
||||
/* Linearize sRGB (inverse gamma) */
|
||||
r = r > 0.04045f ? powf((r + 0.055f) / 1.055f, 2.4f) : r / 12.92f;
|
||||
g = g > 0.04045f ? powf((g + 0.055f) / 1.055f, 2.4f) : g / 12.92f;
|
||||
b = b > 0.04045f ? powf((b + 0.055f) / 1.055f, 2.4f) : b / 12.92f;
|
||||
|
||||
/* Linear RGB to XYZ (sRGB matrix, D65 illuminant) */
|
||||
float x = (r * 0.4124564f + g * 0.3575761f + b * 0.1804375f) / 0.95047f;
|
||||
float y = r * 0.2126729f + g * 0.7151522f + b * 0.0721750f;
|
||||
float z = (r * 0.0193339f + g * 0.1191920f + b * 0.9503041f) / 1.08883f;
|
||||
|
||||
/* XYZ to LAB */
|
||||
x = x > 0.008856f ? cbrtf(x) : 7.787f * x + 16.0f / 116.0f;
|
||||
y = y > 0.008856f ? cbrtf(y) : 7.787f * y + 16.0f / 116.0f;
|
||||
z = z > 0.008856f ? cbrtf(z) : 7.787f * z + 16.0f / 116.0f;
|
||||
|
||||
return (struct lab){
|
||||
.l = 116.0f * y - 16.0f,
|
||||
.a = 500.0f * (x - y),
|
||||
.b = 200.0f * (y - z),
|
||||
};
|
||||
}
|
||||
|
||||
uint32_t
|
||||
lab_to_rgb(struct lab c)
|
||||
{
|
||||
/* LAB to XYZ */
|
||||
float y = (c.l + 16.0f) / 116.0f;
|
||||
float x = c.a / 500.0f + y;
|
||||
float z = y - c.b / 200.0f;
|
||||
|
||||
float x3 = x * x * x;
|
||||
float y3 = y * y * y;
|
||||
float z3 = z * z * z;
|
||||
|
||||
float xf = (x3 > 0.008856f ? x3 : (x - 16.0f / 116.0f) / 7.787f) * 0.95047f;
|
||||
float yf = y3 > 0.008856f ? y3 : (y - 16.0f / 116.0f) / 7.787f;
|
||||
float zf = (z3 > 0.008856f ? z3 : (z - 16.0f / 116.0f) / 7.787f) * 1.08883f;
|
||||
|
||||
/* XYZ to linear RGB (inverse sRGB matrix) */
|
||||
float r = xf * 3.2404542f - yf * 1.5371385f - zf * 0.4985314f;
|
||||
float g = xf * -0.9692660f + yf * 1.8760108f + zf * 0.0415560f;
|
||||
float b = xf * 0.0556434f - yf * 0.2040259f + zf * 1.0572252f;
|
||||
|
||||
/* Apply sRGB gamma */
|
||||
r = r > 0.0031308f ? 1.055f * powf(r, 1.0f / 2.4f) - 0.055f : 12.92f * r;
|
||||
g = g > 0.0031308f ? 1.055f * powf(g, 1.0f / 2.4f) - 0.055f : 12.92f * g;
|
||||
b = b > 0.0031308f ? 1.055f * powf(b, 1.0f / 2.4f) - 0.055f : 12.92f * b;
|
||||
|
||||
/* Clamp and quantize */
|
||||
if (r < 0.0f) r = 0.0f; else if (r > 1.0f) r = 1.0f;
|
||||
if (g < 0.0f) g = 0.0f; else if (g > 1.0f) g = 1.0f;
|
||||
if (b < 0.0f) b = 0.0f; else if (b > 1.0f) b = 1.0f;
|
||||
|
||||
return (uint32_t)((uint8_t)(r * 255.0f + 0.5f) << 16 |
|
||||
(uint8_t)(g * 255.0f + 0.5f) << 8 |
|
||||
(uint8_t)(b * 255.0f + 0.5f));
|
||||
}
|
||||
|
||||
struct lab
|
||||
lab_lerp(float t, struct lab a, struct lab b)
|
||||
{
|
||||
return (struct lab){
|
||||
.l = a.l + t * (b.l - a.l),
|
||||
.a = a.a + t * (b.a - a.a),
|
||||
.b = a.b + t * (b.b - a.b),
|
||||
};
|
||||
}
|
||||
13
lab.h
Normal file
13
lab.h
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct lab {
|
||||
float l;
|
||||
float a;
|
||||
float b;
|
||||
};
|
||||
|
||||
struct lab lab_from_rgb(uint32_t rgb);
|
||||
uint32_t lab_to_rgb(struct lab c);
|
||||
struct lab lab_lerp(float t, struct lab a, struct lab b);
|
||||
|
|
@ -250,6 +250,7 @@ common = static_library(
|
|||
misc = static_library(
|
||||
'misc',
|
||||
'hsl.c', 'hsl.h',
|
||||
'lab.c', 'lab.h',
|
||||
'macros.h',
|
||||
'misc.c', 'misc.h',
|
||||
'uri.c', 'uri.h',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue