mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 07:46:12 +03:00
fix the baseline for font rendering
This commit is contained in:
@ -44,6 +44,7 @@ flat out uint mode;
|
|||||||
uniform sampler2D text;
|
uniform sampler2D text;
|
||||||
uniform vec2 cell_size;
|
uniform vec2 cell_size;
|
||||||
uniform mat4 projection;
|
uniform mat4 projection;
|
||||||
|
uniform float glyph_baseline;
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Modes
|
* Modes
|
||||||
@ -99,11 +100,12 @@ void main() {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case MODE_FG:
|
case MODE_FG:
|
||||||
// The glyph offset is upside down so we need to reverse it to
|
// The glyph_offset.y is the y bearing, a y value that when added
|
||||||
// be based on the offset of our cell. This is equivalent to
|
// to the baseline is the offset (+y is up). Our grid goes down.
|
||||||
// "1 - value" to flip the value.
|
// So we flip it with `cell_size.y - glyph_offset.y`. The glyph_baseline
|
||||||
|
// uniform sets our line baseline where characters "sit".
|
||||||
vec2 glyph_offset_calc = glyph_offset;
|
vec2 glyph_offset_calc = glyph_offset;
|
||||||
glyph_offset_calc.y = cell_size.y - glyph_offset.y;
|
glyph_offset_calc.y = cell_size.y - glyph_offset.y - glyph_baseline;
|
||||||
|
|
||||||
// Calculate the final position of the cell.
|
// Calculate the final position of the cell.
|
||||||
cell_pos = cell_pos + glyph_size * position + glyph_offset_calc;
|
cell_pos = cell_pos + glyph_size * position + glyph_offset_calc;
|
||||||
|
@ -42,7 +42,7 @@ pub const Glyph = struct {
|
|||||||
offset_y: i32,
|
offset_y: i32,
|
||||||
|
|
||||||
/// coordinates in the atlas of the top-left corner. These have to
|
/// coordinates in the atlas of the top-left corner. These have to
|
||||||
/// be normalized to be between 0 and 1 prior to use.
|
/// be normalized to be between 0 and 1 prior to use in shaders.
|
||||||
atlas_x: u32,
|
atlas_x: u32,
|
||||||
atlas_y: u32,
|
atlas_y: u32,
|
||||||
|
|
||||||
|
21
src/Grid.zig
21
src/Grid.zig
@ -95,14 +95,19 @@ pub fn init(alloc: Allocator) !Grid {
|
|||||||
// The cell height is the vertical height required to render underscore
|
// The cell height is the vertical height required to render underscore
|
||||||
// '_' which should live at the bottom of a cell.
|
// '_' which should live at the bottom of a cell.
|
||||||
const cell_height: f32 = cell_height: {
|
const cell_height: f32 = cell_height: {
|
||||||
// TODO(render): kitty does a calculation based on other font
|
// This is the height reported by the font face
|
||||||
// metrics that we probably want to research more. For now, this is
|
const face_height: i32 = font.ft_face.*.height >> 6;
|
||||||
// fine.
|
|
||||||
|
// Determine the height of the underscore char
|
||||||
assert(font.ft_face != null);
|
assert(font.ft_face != null);
|
||||||
const glyph = font.getGlyph('_').?;
|
const glyph = font.getGlyph('_').?;
|
||||||
var res: i32 = font.ft_face.*.ascender >> 6;
|
var res: i32 = font.ft_face.*.ascender >> 6;
|
||||||
res -= glyph.offset_y;
|
res -= glyph.offset_y;
|
||||||
res += @intCast(i32, glyph.height);
|
res += @intCast(i32, glyph.height);
|
||||||
|
|
||||||
|
// We take whatever is larger to account for some fonts that
|
||||||
|
// put the underscore outside f the rectangle.
|
||||||
|
if (res < face_height) res = face_height;
|
||||||
break :cell_height @intToFloat(f32, res);
|
break :cell_height @intToFloat(f32, res);
|
||||||
};
|
};
|
||||||
log.debug("cell dimensions w={d} h={d}", .{ cell_width, cell_height });
|
log.debug("cell dimensions w={d} h={d}", .{ cell_width, cell_height });
|
||||||
@ -117,6 +122,10 @@ pub fn init(alloc: Allocator) !Grid {
|
|||||||
const pbind = try program.use();
|
const pbind = try program.use();
|
||||||
defer pbind.unbind();
|
defer pbind.unbind();
|
||||||
try program.setUniform("cell_size", @Vector(2, f32){ cell_width, cell_height });
|
try program.setUniform("cell_size", @Vector(2, f32){ cell_width, cell_height });
|
||||||
|
try program.setUniform(
|
||||||
|
"glyph_baseline",
|
||||||
|
cell_height - @intToFloat(f32, font.ft_face.*.ascender >> 6),
|
||||||
|
);
|
||||||
|
|
||||||
// Setup our VAO
|
// Setup our VAO
|
||||||
const vao = try gl.VertexArray.create();
|
const vao = try gl.VertexArray.create();
|
||||||
@ -258,6 +267,7 @@ pub fn updateCells(self: *Grid, term: Terminal) !void {
|
|||||||
|
|
||||||
// TODO: for background colors, add another cell with mode = 1
|
// TODO: for background colors, add another cell with mode = 1
|
||||||
self.cells.appendAssumeCapacity(.{
|
self.cells.appendAssumeCapacity(.{
|
||||||
|
.mode = 2,
|
||||||
.grid_col = @intCast(u16, x),
|
.grid_col = @intCast(u16, x),
|
||||||
.grid_row = @intCast(u16, y),
|
.grid_row = @intCast(u16, y),
|
||||||
.glyph_x = glyph.atlas_x,
|
.glyph_x = glyph.atlas_x,
|
||||||
@ -274,13 +284,13 @@ pub fn updateCells(self: *Grid, term: Terminal) !void {
|
|||||||
.bg_g = 0xA5,
|
.bg_g = 0xA5,
|
||||||
.bg_b = 0,
|
.bg_b = 0,
|
||||||
.bg_a = 0,
|
.bg_a = 0,
|
||||||
.mode = 2,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the cursor
|
// Draw the cursor
|
||||||
self.cells.appendAssumeCapacity(.{
|
self.cells.appendAssumeCapacity(.{
|
||||||
|
.mode = 1,
|
||||||
.grid_col = @intCast(u16, term.cursor.x),
|
.grid_col = @intCast(u16, term.cursor.x),
|
||||||
.grid_row = @intCast(u16, term.cursor.y),
|
.grid_row = @intCast(u16, term.cursor.y),
|
||||||
.fg_r = 0,
|
.fg_r = 0,
|
||||||
@ -291,7 +301,6 @@ pub fn updateCells(self: *Grid, term: Terminal) !void {
|
|||||||
.bg_g = 0xFF,
|
.bg_g = 0xFF,
|
||||||
.bg_b = 0xFF,
|
.bg_b = 0xFF,
|
||||||
.bg_a = 255,
|
.bg_a = 255,
|
||||||
.mode = 1,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,7 +325,7 @@ pub fn setScreenSize(self: *Grid, dim: ScreenSize) !void {
|
|||||||
// Recalculate the rows/columns.
|
// Recalculate the rows/columns.
|
||||||
self.size.update(dim, self.cell_size);
|
self.size.update(dim, self.cell_size);
|
||||||
|
|
||||||
log.debug("screen size screen={} grid={}", .{ dim, self.size });
|
log.debug("screen size screen={} grid={}, cell={}", .{ dim, self.size, self.cell_size });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(self: Grid) !void {
|
pub fn render(self: Grid) !void {
|
||||||
|
@ -83,6 +83,7 @@ pub inline fn setUniform(p: Program, n: [:0]const u8, value: anytype) !void {
|
|||||||
// Perform the correct call depending on the type of the value.
|
// Perform the correct call depending on the type of the value.
|
||||||
switch (@TypeOf(value)) {
|
switch (@TypeOf(value)) {
|
||||||
comptime_int => c.glUniform1i(loc, value),
|
comptime_int => c.glUniform1i(loc, value),
|
||||||
|
f32 => c.glUniform1f(loc, value),
|
||||||
@Vector(2, f32) => c.glUniform2f(loc, value[0], value[1]),
|
@Vector(2, f32) => c.glUniform2f(loc, value[0], value[1]),
|
||||||
@Vector(3, f32) => c.glUniform3f(loc, value[0], value[1], value[2]),
|
@Vector(3, f32) => c.glUniform3f(loc, value[0], value[1], value[2]),
|
||||||
@Vector(4, f32) => c.glUniform4f(loc, value[0], value[1], value[2], value[3]),
|
@Vector(4, f32) => c.glUniform4f(loc, value[0], value[1], value[2], value[3]),
|
||||||
|
Reference in New Issue
Block a user