mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-14 19:45:49 +00:00
refactor 256 color gen
This commit is contained in:
committed by
Mitchell Hashimoto
parent
5f89228a7a
commit
7729714935
@@ -22,7 +22,6 @@ const fontpkg = @import("../font/main.zig");
|
||||
const inputpkg = @import("../input.zig");
|
||||
const internal_os = @import("../os/main.zig");
|
||||
const cli = @import("../cli.zig");
|
||||
const Lab = @import("../lab.zig").Lab;
|
||||
|
||||
const conditional = @import("conditional.zig");
|
||||
const Conditional = conditional.Conditional;
|
||||
@@ -5614,50 +5613,6 @@ pub const Palette = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate(
|
||||
self: Self,
|
||||
bg: terminal.color.RGB,
|
||||
fg: terminal.color.RGB
|
||||
) terminal.color.Palette {
|
||||
var result = self.value;
|
||||
var base8_lab: [8]Lab = undefined;
|
||||
for (0..8) |i| base8_lab[i] = Lab.fromTerminalRgb(result[i]);
|
||||
const bg_lab = Lab.fromTerminalRgb(bg);
|
||||
const fg_lab = Lab.fromTerminalRgb(fg);
|
||||
|
||||
var idx: usize = 16;
|
||||
for (0..6) |ri| {
|
||||
const tr = @as(f32, @floatFromInt(ri)) / 5.0;
|
||||
const c0 = Lab.lerp(tr, bg_lab, base8_lab[1]);
|
||||
const c1 = Lab.lerp(tr, base8_lab[2], base8_lab[3]);
|
||||
const c2 = Lab.lerp(tr, base8_lab[4], base8_lab[5]);
|
||||
const c3 = Lab.lerp(tr, base8_lab[6], fg_lab);
|
||||
for (0..6) |gi| {
|
||||
const tg = @as(f32, @floatFromInt(gi)) / 5.0;
|
||||
const c4 = Lab.lerp(tg, c0, c1);
|
||||
const c5 = Lab.lerp(tg, c2, c3);
|
||||
for (0..6) |bi| {
|
||||
if (!self.mask.isSet(idx)) {
|
||||
const c6 = Lab.lerp(
|
||||
@as(f32, @floatFromInt(bi)) / 5.0, c4, c5);
|
||||
result[idx] = c6.toTerminalRgb();
|
||||
}
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (0..24) |i| {
|
||||
const t = @as(f32, @floatFromInt(i + 1)) / 25.0;
|
||||
if (!self.mask.isSet(idx)) {
|
||||
result[idx] = Lab.lerp(t, bg_lab, fg_lab).toTerminalRgb();
|
||||
}
|
||||
idx += 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
test "parseCLI" {
|
||||
const testing = std.testing;
|
||||
|
||||
|
||||
67
src/lab.zig
67
src/lab.zig
@@ -1,67 +0,0 @@
|
||||
const terminal = @import("./terminal/main.zig");
|
||||
const std = @import("std");
|
||||
|
||||
pub const Lab = struct {
|
||||
l: f32,
|
||||
a: f32,
|
||||
b: f32,
|
||||
|
||||
pub fn fromTerminalRgb(rgb: terminal.color.RGB) Lab {
|
||||
var r: f32 = @as(f32, @floatFromInt(rgb.r)) / 255.0;
|
||||
var g: f32 = @as(f32, @floatFromInt(rgb.g)) / 255.0;
|
||||
var b: f32 = @as(f32, @floatFromInt(rgb.b)) / 255.0;
|
||||
|
||||
r = if (r > 0.04045) std.math.pow(f32, (r + 0.055) / 1.055, 2.4) else r / 12.92;
|
||||
g = if (g > 0.04045) std.math.pow(f32, (g + 0.055) / 1.055, 2.4) else g / 12.92;
|
||||
b = if (b > 0.04045) std.math.pow(f32, (b + 0.055) / 1.055, 2.4) else b / 12.92;
|
||||
|
||||
var x = (r * 0.4124564 + g * 0.3575761 + b * 0.1804375) / 0.95047;
|
||||
var y = r * 0.2126729 + g * 0.7151522 + b * 0.0721750;
|
||||
var z = (r * 0.0193339 + g * 0.1191920 + b * 0.9503041) / 1.08883;
|
||||
|
||||
x = if (x > 0.008856) std.math.cbrt(x) else 7.787 * x + 16.0 / 116.0;
|
||||
y = if (y > 0.008856) std.math.cbrt(y) else 7.787 * y + 16.0 / 116.0;
|
||||
z = if (z > 0.008856) std.math.cbrt(z) else 7.787 * z + 16.0 / 116.0;
|
||||
|
||||
return .{ .l = 116.0 * y - 16.0, .a = 500.0 * (x - y), .b = 200.0 * (y - z) };
|
||||
}
|
||||
|
||||
pub fn toTerminalRgb(self: Lab) terminal.color.RGB {
|
||||
const y = (self.l + 16.0) / 116.0;
|
||||
const x = self.a / 500.0 + y;
|
||||
const z = y - self.b / 200.0;
|
||||
|
||||
const x3 = x * x * x;
|
||||
const y3 = y * y * y;
|
||||
const z3 = z * z * z;
|
||||
const xf = (if (x3 > 0.008856) x3 else (x - 16.0 / 116.0) / 7.787) * 0.95047;
|
||||
const yf = if (y3 > 0.008856) y3 else (y - 16.0 / 116.0) / 7.787;
|
||||
const zf = (if (z3 > 0.008856) z3 else (z - 16.0 / 116.0) / 7.787) * 1.08883;
|
||||
|
||||
var r = xf * 3.2404542 - yf * 1.5371385 - zf * 0.4985314;
|
||||
var g = -xf * 0.9692660 + yf * 1.8760108 + zf * 0.0415560;
|
||||
var b = xf * 0.0556434 - yf * 0.2040259 + zf * 1.0572252;
|
||||
|
||||
r = if (r > 0.0031308) 1.055 * std.math.pow(f32, r, 1.0 / 2.4) - 0.055 else 12.92 * r;
|
||||
g = if (g > 0.0031308) 1.055 * std.math.pow(f32, g, 1.0 / 2.4) - 0.055 else 12.92 * g;
|
||||
b = if (b > 0.0031308) 1.055 * std.math.pow(f32, b, 1.0 / 2.4) - 0.055 else 12.92 * b;
|
||||
|
||||
return .{
|
||||
.r = @intFromFloat(@min(@max(r, 0.0), 1.0) * 255.0 + 0.5),
|
||||
.g = @intFromFloat(@min(@max(g, 0.0), 1.0) * 255.0 + 0.5),
|
||||
.b = @intFromFloat(@min(@max(b, 0.0), 1.0) * 255.0 + 0.5),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn lerp(t: f32, a: Lab, b: Lab) Lab {
|
||||
return .{
|
||||
.l = a.l + t * (b.l - a.l),
|
||||
.a = a.a + t * (b.a - a.a),
|
||||
.b = a.b + t * (b.b - a.b)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -47,6 +47,51 @@ pub const default: Palette = default: {
|
||||
/// Palette is the 256 color palette.
|
||||
pub const Palette = [256]RGB;
|
||||
|
||||
pub fn generate_256_palette(
|
||||
base: Palette,
|
||||
mask: std.StaticBitSet(@typeInfo(Palette).array.len),
|
||||
bg: RGB,
|
||||
fg: RGB
|
||||
) Palette {
|
||||
var palette = base;
|
||||
var base8_lab: [8]LAB = undefined;
|
||||
for (0..8) |i| base8_lab[i] = LAB.fromRgb(palette[i]);
|
||||
const bg_lab = LAB.fromRgb(bg);
|
||||
const fg_lab = LAB.fromRgb(fg);
|
||||
|
||||
var idx: usize = 16;
|
||||
for (0..6) |ri| {
|
||||
const tr = @as(f32, @floatFromInt(ri)) / 5.0;
|
||||
const c0 = LAB.lerp(tr, bg_lab, base8_lab[1]);
|
||||
const c1 = LAB.lerp(tr, base8_lab[2], base8_lab[3]);
|
||||
const c2 = LAB.lerp(tr, base8_lab[4], base8_lab[5]);
|
||||
const c3 = LAB.lerp(tr, base8_lab[6], fg_lab);
|
||||
for (0..6) |gi| {
|
||||
const tg = @as(f32, @floatFromInt(gi)) / 5.0;
|
||||
const c4 = LAB.lerp(tg, c0, c1);
|
||||
const c5 = LAB.lerp(tg, c2, c3);
|
||||
for (0..6) |bi| {
|
||||
if (!mask.isSet(idx)) {
|
||||
const c6 = LAB.lerp(
|
||||
@as(f32, @floatFromInt(bi)) / 5.0, c4, c5);
|
||||
palette[idx] = c6.toRgb();
|
||||
}
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (0..24) |i| {
|
||||
const t = @as(f32, @floatFromInt(i + 1)) / 25.0;
|
||||
if (!mask.isSet(idx)) {
|
||||
palette[idx] = LAB.lerp(t, bg_lab, fg_lab).toRgb();
|
||||
}
|
||||
idx += 1;
|
||||
}
|
||||
|
||||
return palette;
|
||||
}
|
||||
|
||||
/// A palette that can have its colors changed and reset. Purposely built
|
||||
/// for terminal color operations.
|
||||
pub const DynamicPalette = struct {
|
||||
@@ -519,6 +564,69 @@ pub const RGB = packed struct(u24) {
|
||||
}
|
||||
};
|
||||
|
||||
/// LAB color space
|
||||
const LAB = struct {
|
||||
l: f32,
|
||||
a: f32,
|
||||
b: f32,
|
||||
|
||||
pub fn fromRgb(rgb: RGB) LAB {
|
||||
var r: f32 = @as(f32, @floatFromInt(rgb.r)) / 255.0;
|
||||
var g: f32 = @as(f32, @floatFromInt(rgb.g)) / 255.0;
|
||||
var b: f32 = @as(f32, @floatFromInt(rgb.b)) / 255.0;
|
||||
|
||||
r = if (r > 0.04045) std.math.pow(f32, (r + 0.055) / 1.055, 2.4) else r / 12.92;
|
||||
g = if (g > 0.04045) std.math.pow(f32, (g + 0.055) / 1.055, 2.4) else g / 12.92;
|
||||
b = if (b > 0.04045) std.math.pow(f32, (b + 0.055) / 1.055, 2.4) else b / 12.92;
|
||||
|
||||
var x = (r * 0.4124564 + g * 0.3575761 + b * 0.1804375) / 0.95047;
|
||||
var y = r * 0.2126729 + g * 0.7151522 + b * 0.0721750;
|
||||
var z = (r * 0.0193339 + g * 0.1191920 + b * 0.9503041) / 1.08883;
|
||||
|
||||
x = if (x > 0.008856) std.math.cbrt(x) else 7.787 * x + 16.0 / 116.0;
|
||||
y = if (y > 0.008856) std.math.cbrt(y) else 7.787 * y + 16.0 / 116.0;
|
||||
z = if (z > 0.008856) std.math.cbrt(z) else 7.787 * z + 16.0 / 116.0;
|
||||
|
||||
return .{ .l = 116.0 * y - 16.0, .a = 500.0 * (x - y), .b = 200.0 * (y - z) };
|
||||
}
|
||||
|
||||
pub fn toRgb(self: LAB) RGB {
|
||||
const y = (self.l + 16.0) / 116.0;
|
||||
const x = self.a / 500.0 + y;
|
||||
const z = y - self.b / 200.0;
|
||||
|
||||
const x3 = x * x * x;
|
||||
const y3 = y * y * y;
|
||||
const z3 = z * z * z;
|
||||
const xf = (if (x3 > 0.008856) x3 else (x - 16.0 / 116.0) / 7.787) * 0.95047;
|
||||
const yf = if (y3 > 0.008856) y3 else (y - 16.0 / 116.0) / 7.787;
|
||||
const zf = (if (z3 > 0.008856) z3 else (z - 16.0 / 116.0) / 7.787) * 1.08883;
|
||||
|
||||
var r = xf * 3.2404542 - yf * 1.5371385 - zf * 0.4985314;
|
||||
var g = -xf * 0.9692660 + yf * 1.8760108 + zf * 0.0415560;
|
||||
var b = xf * 0.0556434 - yf * 0.2040259 + zf * 1.0572252;
|
||||
|
||||
r = if (r > 0.0031308) 1.055 * std.math.pow(f32, r, 1.0 / 2.4) - 0.055 else 12.92 * r;
|
||||
g = if (g > 0.0031308) 1.055 * std.math.pow(f32, g, 1.0 / 2.4) - 0.055 else 12.92 * g;
|
||||
b = if (b > 0.0031308) 1.055 * std.math.pow(f32, b, 1.0 / 2.4) - 0.055 else 12.92 * b;
|
||||
|
||||
return .{
|
||||
.r = @intFromFloat(@min(@max(r, 0.0), 1.0) * 255.0 + 0.5),
|
||||
.g = @intFromFloat(@min(@max(g, 0.0), 1.0) * 255.0 + 0.5),
|
||||
.b = @intFromFloat(@min(@max(b, 0.0), 1.0) * 255.0 + 0.5),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn lerp(t: f32, a: LAB, b: LAB) LAB {
|
||||
return .{
|
||||
.l = a.l + t * (b.l - a.l),
|
||||
.a = a.a + t * (b.a - a.a),
|
||||
.b = a.b + t * (b.b - a.b)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
test "palette: default" {
|
||||
const testing = std.testing;
|
||||
|
||||
|
||||
@@ -176,7 +176,9 @@ pub const DerivedConfig = struct {
|
||||
const alloc = arena.allocator();
|
||||
|
||||
const palette = if (config.@"generate-256-palette")
|
||||
config.palette.generate(
|
||||
terminalpkg.color.generate_256_palette(
|
||||
config.palette.value,
|
||||
config.palette.mask,
|
||||
config.background.toTerminalRGB(),
|
||||
config.foreground.toTerminalRGB()
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user