summaryrefslogtreecommitdiff
path: root/src/palette.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/palette.c')
-rw-r--r--src/palette.c213
1 files changed, 100 insertions, 113 deletions
diff --git a/src/palette.c b/src/palette.c
index 1b27e3a..a8add4e 100644
--- a/src/palette.c
+++ b/src/palette.c
@@ -117,48 +117,44 @@ void term_theme_high_contrast(struct term_theme *theme)
/* Finds the slot for key and the default it resets to. Keys are
* foreground, background, and color0 to color15. */
-static bool palette_slot(struct term_theme *p, const struct term_theme *def,
- const char *key, uint32_t **slot,
- const uint32_t **fallback)
+static uint32_t *palette_slot(struct term_theme *p, const char *key,
+ uint32_t *fallback)
{
if (!strcmp(key, "foreground")) {
- *slot = &p->fg;
- *fallback = &def->fg;
- return true;
+ *fallback = builtin_theme.fg;
+ return &p->fg;
}
if (!strcmp(key, "background")) {
- *slot = &p->bg;
- *fallback = &def->bg;
- return true;
+ *fallback = builtin_theme.bg;
+ return &p->bg;
}
if (strncmp(key, "color", 5))
- return false;
+ return NULL;
const char *digits = key + 5;
if (!*digits || (*digits == '0' && digits[1]))
- return false;
+ return NULL;
int i = 0;
for (const char *d = digits; *d; d++) {
if (*d < '0' || *d > '9')
- return false;
+ return NULL;
i = i * 10 + (*d - '0');
if (i > 15)
- return false;
+ return NULL;
}
- *slot = &p->ansi[i];
- *fallback = &def->ansi[i];
- return true;
+ *fallback = builtin_theme.ansi[i];
+ return &p->ansi[i];
}
bool term_theme_set_key(struct term_theme *p, const char *key, const char *val)
{
- struct term_theme def;
- term_theme_default(&def);
- uint32_t *slot;
- const uint32_t *fallback;
- if (!palette_slot(p, &def, key, &slot, &fallback))
+ if (!p || !key || !val)
+ return false;
+ uint32_t fallback;
+ uint32_t *slot = palette_slot(p, key, &fallback);
+ if (!slot)
return false;
if (!val[0]) {
- *slot = *fallback;
+ *slot = fallback;
return true;
}
uint32_t v;
@@ -187,7 +183,6 @@ static bool parse_hex_channel(const char *s, size_t len, uint8_t *out)
static bool parse_fraction(const char *s, size_t len, uint8_t *out)
{
-
if (len == 0)
return false;
bool seen_digit = false;
@@ -195,12 +190,7 @@ static bool parse_fraction(const char *s, size_t len, uint8_t *out)
unsigned integer = 0;
unsigned frac = 0;
unsigned frac_digits = 0;
- size_t i = 0;
- if (s[0] == '.') {
- seen_dot = true;
- i = 1;
- }
- for (; i < len; i++) {
+ for (size_t i = 0; i < len; i++) {
char c = s[i];
if (c >= '0' && c <= '9') {
seen_digit = true;
@@ -222,14 +212,12 @@ static bool parse_fraction(const char *s, size_t len, uint8_t *out)
}
if (!seen_digit)
return false;
- double value = (double)integer;
- if (frac_digits > 0) {
- double f = (double)frac;
- for (unsigned k = 0; k < frac_digits; k++)
- f /= 10.0;
- value += f;
- }
- if (value > 1.0) value = 1.0;
+ static const double pow10[10] = {
+ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+ };
+ double value = (double)integer + (double)frac / pow10[frac_digits];
+ if (value > 1.0)
+ value = 1.0;
*out = (uint8_t)(value * 255.0 + 0.5);
return true;
}
@@ -249,6 +237,17 @@ static size_t rtrimmed_len(const char *s)
return n;
}
+static bool parse_hex_rgb(const char *s, size_t cw, uint32_t *out)
+{
+ uint8_t r, g, b;
+ if (!parse_hex_channel(s, cw, &r) ||
+ !parse_hex_channel(s + cw, cw, &g) ||
+ !parse_hex_channel(s + 2 * cw, cw, &b))
+ return false;
+ *out = term_rgb(r, g, b);
+ return true;
+}
+
bool term_color_parse(const char *input, uint32_t *out)
{
if (!input || !out)
@@ -259,18 +258,10 @@ bool term_color_parse(const char *input, uint32_t *out)
return false;
if (s[0] == '#') {
- const char *body = s + 1;
size_t blen = len - 1;
- size_t cw = blen / 3;
if (blen != 3 && blen != 6 && blen != 9 && blen != 12)
return false;
- uint8_t r, g, b;
- if (!parse_hex_channel(body, cw, &r) ||
- !parse_hex_channel(body + cw, cw, &g) ||
- !parse_hex_channel(body + 2 * cw, cw, &b))
- return false;
- *out = term_rgb(r, g, b);
- return true;
+ return parse_hex_rgb(s + 1, blen / 3, out);
}
if (len >= 4 && (s[0] == 'r' || s[0] == 'R') &&
@@ -303,51 +294,55 @@ bool term_color_parse(const char *input, uint32_t *out)
}
if (ci != 3)
return false;
- uint8_t r, g, b;
- if (intensity) {
- if (!parse_fraction(channels[0], chlens[0], &r) ||
- !parse_fraction(channels[1], chlens[1], &g) ||
- !parse_fraction(channels[2], chlens[2], &b))
- return false;
- } else {
- if (!parse_hex_channel(channels[0], chlens[0], &r) ||
- !parse_hex_channel(channels[1], chlens[1], &g) ||
- !parse_hex_channel(channels[2], chlens[2], &b))
+ uint8_t c[3];
+ for (int k = 0; k < 3; k++) {
+ bool ok = intensity
+ ? parse_fraction(channels[k], chlens[k], &c[k])
+ : parse_hex_channel(channels[k], chlens[k], &c[k]);
+ if (!ok)
return false;
}
- *out = term_rgb(r, g, b);
+ *out = term_rgb(c[0], c[1], c[2]);
return true;
}
- if (len == 6 || len == 3) {
- uint8_t r, g, b;
- size_t cw = len / 3;
- if (!parse_hex_channel(s, cw, &r) ||
- !parse_hex_channel(s + cw, cw, &g) ||
- !parse_hex_channel(s + 2 * cw, cw, &b))
- return false;
- *out = term_rgb(r, g, b);
- return true;
- }
+ if (len == 6 || len == 3)
+ return parse_hex_rgb(s, len / 3, out);
return false;
}
struct lab { float l, a, b; };
+static inline float lab_f(float t)
+{
+ return t > 0.008856f ? cbrtf(t) : 7.787f * t + 16.0f / 116.0f;
+}
+
+static inline float lab_f_inv(float t)
+{
+ float t3 = t * t * t;
+ return t3 > 0.008856f ? t3 : (t - 16.0f / 116.0f) / 7.787f;
+}
+
+static inline uint8_t quantize_channel(float c)
+{
+ if (c < 0.0f)
+ return 0;
+ if (c > 1.0f)
+ return 255;
+ return (uint8_t)(c * 255.0f + 0.5f);
+}
+
static struct lab lab_from_rgb(uint32_t argb)
{
float r = srgb_linear[(argb >> 16) & 0xFF];
float g = srgb_linear[(argb >> 8) & 0xFF];
float b = srgb_linear[argb & 0xFF];
- 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;
-
- 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;
+ float x = lab_f((r * 0.4124564f + g * 0.3575761f + b * 0.1804375f) / 0.95047f);
+ float y = lab_f(r * 0.2126729f + g * 0.7151522f + b * 0.0721750f);
+ float z = lab_f((r * 0.0193339f + g * 0.1191920f + b * 0.9503041f) / 1.08883f);
struct lab lab;
lab.l = 116.0f * y - 16.0f;
@@ -362,32 +357,15 @@ static uint32_t lab_to_rgb(struct lab lab)
float x = lab.a / 500.0f + y;
float z = y - lab.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;
-
- 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;
-
- r = linf_to_srgbf(r);
- g = linf_to_srgbf(g);
- b = linf_to_srgbf(b);
-
- if (r < 0.0f) r = 0.0f;
- if (r > 1.0f) r = 1.0f;
- if (g < 0.0f) g = 0.0f;
- if (g > 1.0f) g = 1.0f;
- if (b < 0.0f) b = 0.0f;
- if (b > 1.0f) b = 1.0f;
-
- uint8_t rb = (uint8_t)(r * 255.0f + 0.5f);
- uint8_t gb = (uint8_t)(g * 255.0f + 0.5f);
- uint8_t bb = (uint8_t)(b * 255.0f + 0.5f);
- return term_rgb(rb, gb, bb);
+ float xf = lab_f_inv(x) * 0.95047f;
+ float yf = lab_f_inv(y);
+ float zf = lab_f_inv(z) * 1.08883f;
+
+ float r = linf_to_srgbf(xf * 3.2404542f - yf * 1.5371385f - zf * 0.4985314f);
+ float g = linf_to_srgbf(-xf * 0.9692660f + yf * 1.8760108f + zf * 0.0415560f);
+ float b = linf_to_srgbf(xf * 0.0556434f - yf * 0.2040259f + zf * 1.0572252f);
+
+ return term_rgb(quantize_channel(r), quantize_channel(g), quantize_channel(b));
}
static struct lab lab_lerp(float t, struct lab a, struct lab b)
@@ -426,22 +404,31 @@ static void derive_palette(uint32_t *p, const struct term_theme *theme)
base8[7] = tmp;
}
- int idx = 16;
- for (int ri = 0; ri < 6; ri++) {
- float tr = (float)ri / 5.0f;
- struct lab c0 = lab_lerp(tr, base8[0], base8[1]);
- struct lab c1 = lab_lerp(tr, base8[2], base8[3]);
- struct lab c2 = lab_lerp(tr, base8[4], base8[5]);
- struct lab c3 = lab_lerp(tr, base8[6], base8[7]);
- for (int gi = 0; gi < 6; gi++) {
- float tg = (float)gi / 5.0f;
- struct lab c4 = lab_lerp(tg, c0, c1);
- struct lab c5 = lab_lerp(tg, c2, c3);
- for (int bi = 0; bi < 6; bi++)
- p[idx++] = lab_to_rgb(lab_lerp((float)bi / 5.0f, c4, c5));
+ static const float steps[6] = { 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f };
+ struct lab c0[6], c1[6], c2[6], c3[6];
+ for (int i = 0; i < 6; i++) {
+ c0[i] = lab_lerp(steps[i], base8[0], base8[1]);
+ c1[i] = lab_lerp(steps[i], base8[2], base8[3]);
+ c2[i] = lab_lerp(steps[i], base8[4], base8[5]);
+ c3[i] = lab_lerp(steps[i], base8[6], base8[7]);
+ }
+
+ struct lab c4[36], c5[36];
+ int k = 0;
+ for (int i = 0; i < 6; i++) {
+ for (int j = 0; j < 6; j++) {
+ c4[k] = lab_lerp(steps[j], c0[i], c1[i]);
+ c5[k] = lab_lerp(steps[j], c2[i], c3[i]);
+ k++;
}
}
+ int idx = 16;
+ for (int i = 0; i < 36; i++) {
+ for (int j = 0; j < 6; j++)
+ p[idx++] = lab_to_rgb(lab_lerp(steps[j], c4[i], c5[i]));
+ }
+
for (int i = 0; i < 24; i++) {
float t = (float)(i + 1) / 25.0f;
p[idx++] = lab_to_rgb(lab_lerp(t, base8[0], base8[7]));