mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-23 12:16:11 +03:00
renderer/metal: minimum contrast experiment
This uses WCAG2 algorithms with a minimum ratio hardcoded of 3:1. This is not shippable in its current state because we want the ratio to be configurable and I'm not happy with the way data is being sent to the shader.
This commit is contained in:
@ -1667,7 +1667,7 @@ pub fn updateCell(
|
||||
const alpha: u8 = if (cell.attrs.faint) 175 else 255;
|
||||
|
||||
// If the cell has a background, we always draw it.
|
||||
if (colors.bg) |rgb| {
|
||||
const bg: [4]u8 = if (colors.bg) |rgb| bg: {
|
||||
// Determine our background alpha. If we have transparency configured
|
||||
// then this is dynamic depending on some situations. This is all
|
||||
// in an attempt to make transparency look the best for various
|
||||
@ -1701,8 +1701,11 @@ pub fn updateCell(
|
||||
.grid_pos = .{ @as(f32, @floatFromInt(x)), @as(f32, @floatFromInt(y)) },
|
||||
.cell_width = cell.widthLegacy(),
|
||||
.color = .{ rgb.r, rgb.g, rgb.b, bg_alpha },
|
||||
.bg_color = .{ 0, 0, 0, 0 },
|
||||
});
|
||||
}
|
||||
|
||||
break :bg .{ rgb.r, rgb.g, rgb.b, bg_alpha };
|
||||
} else .{ 0, 0, 0, 0 };
|
||||
|
||||
// If the cell has a character, draw it
|
||||
if (cell.char > 0) {
|
||||
@ -1729,6 +1732,7 @@ pub fn updateCell(
|
||||
.grid_pos = .{ @as(f32, @floatFromInt(x)), @as(f32, @floatFromInt(y)) },
|
||||
.cell_width = cell.widthLegacy(),
|
||||
.color = .{ colors.fg.r, colors.fg.g, colors.fg.b, alpha },
|
||||
.bg_color = bg,
|
||||
.glyph_pos = .{ glyph.atlas_x, glyph.atlas_y },
|
||||
.glyph_size = .{ glyph.width, glyph.height },
|
||||
.glyph_offset = .{ glyph.offset_x, glyph.offset_y },
|
||||
@ -1759,6 +1763,7 @@ pub fn updateCell(
|
||||
.grid_pos = .{ @as(f32, @floatFromInt(x)), @as(f32, @floatFromInt(y)) },
|
||||
.cell_width = cell.widthLegacy(),
|
||||
.color = .{ color.r, color.g, color.b, alpha },
|
||||
.bg_color = bg,
|
||||
.glyph_pos = .{ glyph.atlas_x, glyph.atlas_y },
|
||||
.glyph_size = .{ glyph.width, glyph.height },
|
||||
.glyph_offset = .{ glyph.offset_x, glyph.offset_y },
|
||||
@ -1771,6 +1776,7 @@ pub fn updateCell(
|
||||
.grid_pos = .{ @as(f32, @floatFromInt(x)), @as(f32, @floatFromInt(y)) },
|
||||
.cell_width = cell.widthLegacy(),
|
||||
.color = .{ colors.fg.r, colors.fg.g, colors.fg.b, alpha },
|
||||
.bg_color = bg,
|
||||
});
|
||||
}
|
||||
|
||||
@ -1834,6 +1840,7 @@ fn addCursor(
|
||||
},
|
||||
.cell_width = if (wide) 2 else 1,
|
||||
.color = .{ color.r, color.g, color.b, alpha },
|
||||
.bg_color = .{ 0, 0, 0, 0 },
|
||||
.glyph_pos = .{ glyph.atlas_x, glyph.atlas_y },
|
||||
.glyph_size = .{ glyph.width, glyph.height },
|
||||
.glyph_offset = .{ glyph.offset_x, glyph.offset_y },
|
||||
@ -1886,6 +1893,7 @@ fn addPreeditCell(
|
||||
.grid_pos = .{ @as(f32, @floatFromInt(x)), @as(f32, @floatFromInt(y)) },
|
||||
.cell_width = if (cp.wide) 2 else 1,
|
||||
.color = .{ bg.r, bg.g, bg.b, 255 },
|
||||
.bg_color = .{ bg.r, bg.g, bg.b, 255 },
|
||||
});
|
||||
|
||||
// Add our text
|
||||
@ -1894,6 +1902,7 @@ fn addPreeditCell(
|
||||
.grid_pos = .{ @as(f32, @floatFromInt(x)), @as(f32, @floatFromInt(y)) },
|
||||
.cell_width = if (cp.wide) 2 else 1,
|
||||
.color = .{ fg.r, fg.g, fg.b, 255 },
|
||||
.bg_color = .{ bg.r, bg.g, bg.b, 255 },
|
||||
.glyph_pos = .{ glyph.atlas_x, glyph.atlas_y },
|
||||
.glyph_size = .{ glyph.width, glyph.height },
|
||||
.glyph_offset = .{ glyph.offset_x, glyph.offset_y },
|
||||
|
@ -95,6 +95,7 @@ pub const Cell = extern struct {
|
||||
glyph_size: [2]u32 = .{ 0, 0 },
|
||||
glyph_offset: [2]i32 = .{ 0, 0 },
|
||||
color: [4]u8,
|
||||
bg_color: [4]u8,
|
||||
cell_width: u8,
|
||||
|
||||
pub const Mode = enum(u8) {
|
||||
@ -401,6 +402,17 @@ fn initCellPipeline(device: objc.Object, library: objc.Object) !objc.Object {
|
||||
attr.setProperty("offset", @as(c_ulong, @offsetOf(Cell, "color")));
|
||||
attr.setProperty("bufferIndex", @as(c_ulong, 0));
|
||||
}
|
||||
{
|
||||
const attr = attrs.msgSend(
|
||||
objc.Object,
|
||||
objc.sel("objectAtIndexedSubscript:"),
|
||||
.{@as(c_ulong, 7)},
|
||||
);
|
||||
|
||||
attr.setProperty("format", @intFromEnum(mtl.MTLVertexFormat.uchar4));
|
||||
attr.setProperty("offset", @as(c_ulong, @offsetOf(Cell, "bg_color")));
|
||||
attr.setProperty("bufferIndex", @as(c_ulong, 0));
|
||||
}
|
||||
{
|
||||
const attr = attrs.msgSend(
|
||||
objc.Object,
|
||||
|
@ -30,6 +30,7 @@ struct VertexIn {
|
||||
uchar4 color [[ attribute(5) ]];
|
||||
|
||||
// The fields below are present only when rendering text.
|
||||
uchar4 bg_color [[ attribute(7) ]];
|
||||
|
||||
// The position of the glyph in the texture (x,y)
|
||||
uint2 glyph_pos [[ attribute(2) ]];
|
||||
@ -49,6 +50,51 @@ struct VertexOut {
|
||||
float2 tex_coord;
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Color Functions
|
||||
//-------------------------------------------------------------------
|
||||
#pragma mark - Colors
|
||||
|
||||
// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
|
||||
float luminance_component(float c) {
|
||||
if (c <= 0.03928f) {
|
||||
return c / 12.92f;
|
||||
} else {
|
||||
return pow((c + 0.055f) / 1.055f, 2.4f);
|
||||
}
|
||||
}
|
||||
|
||||
float relative_luminance(float3 color) {
|
||||
color.r = luminance_component(color.r);
|
||||
color.g = luminance_component(color.g);
|
||||
color.b = luminance_component(color.b);
|
||||
float3 weights = float3(0.2126f, 0.7152f, 0.0722f);
|
||||
return dot(color, weights);
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef
|
||||
float contrast_ratio(float3 color1, float3 color2) {
|
||||
float l1 = relative_luminance(color1);
|
||||
float l2 = relative_luminance(color2);
|
||||
return (max(l1, l2) + 0.05f) / (min(l1, l2) + 0.05f);
|
||||
}
|
||||
|
||||
float4 contrasted_color(float4 fg, float4 bg) {
|
||||
float3 fg_premult = fg.rgb * fg.a;
|
||||
float3 bg_premult = bg.rgb * bg.a;
|
||||
float ratio = contrast_ratio(fg_premult, bg_premult);
|
||||
if (ratio <= 3.0f) {
|
||||
float ratio = contrast_ratio(float3(1.0f), bg_premult);
|
||||
if (ratio > 3.0f) {
|
||||
return float4(1.0f);
|
||||
} else {
|
||||
return float4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
return fg;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Terminal Grid Cell Shader
|
||||
//-------------------------------------------------------------------
|
||||
@ -112,6 +158,8 @@ vertex VertexOut uber_vertex(
|
||||
// Calculate the texture coordinate in pixels. This is NOT normalized
|
||||
// (between 0.0 and 1.0) and must be done in the fragment shader.
|
||||
out.tex_coord = float2(input.glyph_pos) + float2(input.glyph_size) * position;
|
||||
|
||||
out.color = contrasted_color(out.color, float4(input.bg_color) / 255.0f);
|
||||
break;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user